Contract 0xbdec4a045446f583dc564c0a227ffd475b329bf0 5

Txn Hash Method
Block
From
To
Value [Txn Fee]
0x71f3b08125c276f59f3602b7523423f151225051316ac16c59ff470eb22a227aWithdraw228902832022-11-27 2:45:4731 secs ago0x5333c1d733794e02f34d5f0d88c65d03fd2e4db1 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.0035278125 26.5
0xe52ed73b2065db3ffeeb231841ddf0db7f0ace690b8afa7257bb1e5fecf2b9b1Join228902042022-11-27 2:43:073 mins ago0x0660e93da792d900bde54ca01c4a59aba09d1fc5 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.00769645 25
0xff693cc7781bfa777e9a19e464fb0b7885a555fddc9832c2e09929792b8933b4Deposit228901952022-11-27 2:42:493 mins ago0x0660e93da792d900bde54ca01c4a59aba09d1fc5 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.004447825 25
0x962a8911c16849e0f4b302d3b28dcecb7a175d3a795fe486c390838f5432db2dWithdraw228900482022-11-27 2:37:448 mins ago0x0660e93da792d900bde54ca01c4a59aba09d1fc5 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.003065925 25
0xa36c290ea6e5436c81351884c88cbb45cad0d5c69b8e83a56c138a2bad8043bbExit228900442022-11-27 2:37:348 mins ago0x0660e93da792d900bde54ca01c4a59aba09d1fc5 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.012348925 25
0x06a556313cab6acc4214d09cc07a64a0242fce586fb97e90bb597d2fbeeb914eJoin228891342022-11-27 2:06:1939 mins ago0x8074ed7aea09a7f371af44dabd4de6c42839929b IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.00813021286 26.41
0xc2140ff31f3a70aa2557775b22b6e0e2d380bf6bf4ef4d41dbb994a54f5d66acJoin228891272022-11-27 2:06:0540 mins ago0x8074ed7aea09a7f371af44dabd4de6c42839929b IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.00487967006 26.41
0xcbca6d186823842340db9bb90e6820fa5418c0e37247e0bcd67e5a6faaed617cDeposit228891152022-11-27 2:05:4140 mins ago0x8074ed7aea09a7f371af44dabd4de6c42839929b IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.00424707133 26.41
0x0588abcf0a422f89dc578b92d96821e8696a522a44ec45a2002276819e18fbf3Join228883482022-11-27 1:39:121 hr 7 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.008034780626.1
0x205dff3853cc1e50d5ea42b5b3f46af06804a7a708e7ced3cabd89ca1cec6071Deposit228883332022-11-27 1:38:421 hr 7 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.004197219326.1
0x50c37067ca8c97f0ee850dc44d121f3e48eb99df0554fddd8eb7866b6d451608Join228882662022-11-27 1:36:251 hr 9 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.008035093826.1
0x6821c3aefa3d811b83c0c71c5f4d7bb6835c314d905ed06413f86add50d6dc4eDeposit228882502022-11-27 1:35:531 hr 10 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.004197219326.1
0xba33a47305349b431cda380be91c92ab7437b25576521e6286c6262ec361fb0dWithdraw228879092022-11-27 1:24:231 hr 21 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.003474562526.1
0x45f444674cdec5fee08edf3cf4a423bb16ad529c5ea0d416dd1a3a04d3d28500Exit228877752022-11-27 1:19:461 hr 26 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.011693139326.1
0x619ca2fcb6f8f032a2882dc7dc4e61d768b74ff5156baf2341d349cef0abdca4Join228874182022-11-27 1:07:411 hr 38 mins ago0x6776b04c0660f0460a8e09da457fbf819c77dc07 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.00699615927
0x980f36e7763f5c88e073b8bb9e6bffefc0764a3683d508f374ff8db152a5791aJoin228873402022-11-27 1:04:541 hr 41 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.008034780626.1
0x53d3cb281e8248035368e5d641343be6b56f246b42914a43c693c15c72dd85b1Join228873332022-11-27 1:04:401 hr 41 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.008035093826.1
0x7b10967d1bcaf820c69165fce982de32d63883fc23c29ddfbf0c72a18f13c825Harvest Multiple...228873032022-11-27 1:03:371 hr 42 mins ago0x6776b04c0660f0460a8e09da457fbf819c77dc07 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.01382543127
0x074c2e94de3878881252aace76d69604694766d5b2b03267b457146ed5b519fbDeposit228872952022-11-27 1:03:181 hr 43 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.007289625626.1
0x4d8403b9fd319ebebbe1ec5d5c734b93be183ed7675f3de37d3c0aaec07fe8aeJoin228872452022-11-27 1:01:351 hr 44 mins ago0x5333c1d733794e02f34d5f0d88c65d03fd2e4db1 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.007630569 26.5
0x16d7acdcd8b23af541f25a978b1754daffd97830a768997130d9b002e5617186Join228871582022-11-27 0:58:411 hr 47 mins ago0x194772668b6d800ba24d3f910bb004da1a81cc81 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.00844201835 27.425
0xc345335df1f708c2494b960a90ea25be6efef9c59cf39aed2a25c5869c55461aDeposit228871432022-11-27 0:58:111 hr 48 mins ago0x194772668b6d800ba24d3f910bb004da1a81cc81 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.0042615445 26.5
0x38100b2f08604200763716286148d932522e2e215c65e5cd3a4766799d4f6adfWithdraw228871382022-11-27 0:58:011 hr 48 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.005662421126.1
0xfe975649b0ba09248c0aac2519b1d1daf4a2552111c5c4bff599ba6b13da20cdExit228871302022-11-27 0:57:451 hr 48 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.011692826126.1
0xb2381421727fa4e5ca830b78f61568837bf14c1f586b4f1d9a57c53d0ee3fa97Exit228871242022-11-27 0:57:321 hr 48 mins ago0x2f1d2f3699f437da19a5c9c5f253f189e5ec93a2 IN  KyberSwap: Elastic Liquidity Mining0 AVAX0.011693139326.1
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x45f444674cdec5fee08edf3cf4a423bb16ad529c5ea0d416dd1a3a04d3d28500228877752022-11-27 1:19:461 hr 26 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.034114223531060046 AVAX
0xfe975649b0ba09248c0aac2519b1d1daf4a2552111c5c4bff599ba6b13da20cd228871302022-11-27 0:57:451 hr 48 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.425098802079370629 AVAX
0xb2381421727fa4e5ca830b78f61568837bf14c1f586b4f1d9a57c53d0ee3fa97228871242022-11-27 0:57:321 hr 48 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.104683206947561392 AVAX
0x728c66fd7c4efdb3188f4bc4d973502ba9a48811b17a141049b47e83f4553ef9228853782022-11-26 23:58:092 hrs 48 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.097489537613464556 AVAX
0x12c75b3b548fe75d9ec8c1a0fa7896654423955c38d0ffe2fc6160c4fa6b8425228822522022-11-26 22:11:024 hrs 35 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.029213984406522766 AVAX
0x12c75b3b548fe75d9ec8c1a0fa7896654423955c38d0ffe2fc6160c4fa6b8425228822522022-11-26 22:11:024 hrs 35 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.191280246372453177 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.646785065457435335 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.583510341639240262 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.000468373345067656 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca8.237371888833996191 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca3.897938466094789679 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.144195833587019008 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.251440619631632774 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca4.435406311890462708 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.000657110822834569 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca8.186842916228278947 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca41.822922700302062738 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.001345967985461571 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.834213356041795871 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca22.323051798465758593 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca1.01342046118497882 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca1.968897760736941818 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca4.780022137570272962 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.000127473595198433 AVAX
0x10b001e3076948258985e6c19a5be36fc9f7415cd0bd01cc66fbeb666057790a228782532022-11-26 19:53:406 hrs 52 mins ago KyberSwap: Elastic Liquidity Mining 0x226314996cdfa694a196ef5e3d9a26b35bb40eca0.000157454071678854 AVAX
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
KyberSwapElasticLM

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 25 : KyberSwapElasticLM.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import {LMHelper} from './LMHelper.sol';
import {KSMath} from '../libraries/KSMath.sol';
import {IKyberSwapElasticLM} from '../interfaces/liquidityMining/IKyberSwapElasticLM.sol';
import {IKyberRewardLockerV2} from '../interfaces/liquidityMining/IKyberRewardLockerV2.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import {AccessControl} from '@openzeppelin/contracts/access/AccessControl.sol';
import {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';

contract KyberSwapElasticLM is IKyberSwapElasticLM, AccessControl, LMHelper, ReentrancyGuard {
  using EnumerableSet for EnumerableSet.UintSet;
  using SafeERC20 for IERC20Metadata;
  using KSMath for uint256;

  IERC721 public immutable nft;
  // contract for locking reward
  IKyberRewardLockerV2 public immutable rewardLocker;

  // keccak256("OPERATOR") : 0x523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c
  bytes32 internal constant OPERATOR_ROLE =
    0x523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c;
  uint256 internal constant PRECISION = 1e12;

  uint256 public numPools;

  // pId => Pool info
  mapping(uint256 => LMPoolInfo) public pools;

  // nftId => Position info
  mapping(uint256 => PositionInfo) public positions;

  // nftId => pId => Stake info
  mapping(uint256 => mapping(uint256 => StakeInfo)) public stakes;

  // nftId => list of joined pools
  mapping(uint256 => EnumerableSet.UintSet) internal joinedPools;

  // user address => set of nft id which user already deposit into LM contract
  mapping(address => EnumerableSet.UintSet) private depositNFTs;

  mapping(uint256 => bool) public isEmergencyWithdrawnNFT;

  bool public emergencyEnabled;

  modifier checkLength(uint256 a, uint256 b) {
    require(a == b, 'invalid length');
    _;
  }

  constructor(IERC721 _nft, IKyberRewardLockerV2 _rewardLocker) {
    nft = _nft;
    rewardLocker = _rewardLocker;
    _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
    _setupRole(OPERATOR_ROLE, msg.sender);
  }

  /**
   * EXTERNAL FUNCTIONS *************************
   */

  /**
   * @dev receive native reward token
   */
  receive() external payable {}

  /**
   * @dev Set emergencyEnabled flag to true
   */
  function emergencyEnable() public onlyRole(DEFAULT_ADMIN_ROLE) {
    require(!emergencyEnabled, 'Invalid value');
    emergencyEnabled = true;
    emit EmergencyEnabled();
  }

  /**
   * @dev Add a new LM pool
   * @param poolAddress Pool address
   * @param startTime Start time of the pool
   * @param endTime End time of the pool
   * @param vestingDuration Duration of the vesting period
   * @param rewardTokens List of ERC20 reward tokens
   * @param rewardAmounts List of total reward amount for each token
   * @param feeTarget Fee target of the pool
   */
  function addPool(
    address poolAddress,
    uint32 startTime,
    uint32 endTime,
    uint32 vestingDuration,
    address[] calldata rewardTokens,
    uint256[] calldata rewardAmounts,
    uint256 feeTarget
  )
    external
    override
    onlyRole(OPERATOR_ROLE)
    checkLength(rewardTokens.length, rewardAmounts.length)
  {
    require(startTime >= _getBlockTime() && endTime > startTime, 'addPool: invalid times');
    uint256 pId = numPools; // save gas
    LMPoolInfo storage pool = pools[pId];

    pool.poolAddress = poolAddress;
    pool.startTime = startTime;
    pool.endTime = endTime;
    pool.vestingDuration = vestingDuration;
    pool.totalSecondsClaimed = 0;
    pool.feeTarget = feeTarget;

    for (uint256 i = 0; i < rewardTokens.length; i++) {
      if (
        rewardTokens[i] != address(0) &&
        IERC20Metadata(rewardTokens[i]).allowance(address(this), address(rewardLocker)) == 0
      ) {
        IERC20Metadata(rewardTokens[i]).safeIncreaseAllowance(
          address(rewardLocker),
          type(uint256).max
        );
      }
      pool.rewards.push(RewardData(rewardTokens[i], rewardAmounts[i]));
    }
    numPools++;
    emit AddPool(pId, poolAddress, startTime, endTime, vestingDuration, feeTarget);
  }

  /**
   * @dev Renew a pool to start another LM program
   * @param pId Pool id to be renewed
   * @param startTime Start time of the pool
   * @param endTime End time of the pool
   * @param vestingDuration Duration of the vesting period
   * @param rewardAmounts List of total reward amount for each token
   * @param feeTarget Fee target of the pool
   */
  function renewPool(
    uint256 pId,
    uint32 startTime,
    uint32 endTime,
    uint32 vestingDuration,
    uint256[] calldata rewardAmounts,
    uint256 feeTarget
  ) external override onlyRole(OPERATOR_ROLE) {
    LMPoolInfo storage pool = pools[pId];

    // check if pool has not started or already ended
    require(
      pool.startTime > _getBlockTime() || pool.endTime < _getBlockTime(),
      'renew: invalid pool state'
    );
    require(pool.rewards.length == rewardAmounts.length, 'renew: invalid length');
    // check input startTime and endTime
    require(startTime > _getBlockTime() && endTime > startTime, 'renew: invalid times');
    // check pool has stakes
    require(pool.numStakes == 0, 'renew: pool has stakes');

    pool.startTime = startTime;
    pool.endTime = endTime;
    pool.vestingDuration = vestingDuration;
    pool.totalSecondsClaimed = 0;
    pool.feeTarget = feeTarget;

    for (uint256 i = 0; i < rewardAmounts.length; ++i) {
      pool.rewards[i].rewardUnclaimed = rewardAmounts[i];
    }
    emit RenewPool(pId, startTime, endTime, vestingDuration, feeTarget);
  }

  /**
   * @dev Deposit NFTs into the pool
   * @param nftIds List of NFT ids from BasePositionManager
   *
   */
  function deposit(uint256[] calldata nftIds) external override {
    address sender = msg.sender;
    // save gas
    bool _emergencyEnabled = emergencyEnabled;
    // save gas

    for (uint256 i = 0; i < nftIds.length; i++) {
      require(!_emergencyEnabled || !isEmergencyWithdrawnNFT[nftIds[i]], 'Not allowed to deposit');
      require(!_emergencyEnabled || !isEmergencyWithdrawnNFT[nftIds[i]], 'Not allowed to deposit');
      positions[nftIds[i]].owner = sender;
      require(depositNFTs[sender].add(nftIds[i]), 'Fail to add depositNFTs');
      nft.transferFrom(sender, address(this), nftIds[i]);
      emit Deposit(sender, nftIds[i]);
    }
  }

  /**
   * @dev Withdraw NFTs, must exit all pools before call
   * @param nftIds List of NFT ids from BasePositionManager
   */
  function withdraw(uint256[] calldata nftIds) external override {
    address sender = msg.sender;
    for (uint256 i = 0; i < nftIds.length; ++i) {
      PositionInfo storage position = positions[nftIds[i]];
      require(position.owner == sender, 'withdraw: not owner');
      require(joinedPools[nftIds[i]].length() == 0, 'withdraw: not exited yet');
      delete positions[nftIds[i]];
      require(depositNFTs[sender].remove(nftIds[i]), 'Fail to remove depositNFTs');
      nft.transferFrom(address(this), sender, nftIds[i]);
      emit Withdraw(sender, nftIds[i]);
    }
  }

  /**
   * @dev Emergency withdraw NFT position, will not receive any reward
   * @param nftIds NFT id from BasePositionManager
   */
  function emergencyWithdraw(uint256[] calldata nftIds) external {
    address sender = msg.sender;
    // save gas
    bool _emergencyEnabled = emergencyEnabled;

    for (uint256 i = 0; i < nftIds.length; ++i) {
      PositionInfo storage position = positions[nftIds[i]];
      require(position.owner == sender, 'withdraw: not owner');

      isEmergencyWithdrawnNFT[nftIds[i]] = true;
      uint256[] memory values = joinedPools[nftIds[i]].values();
      for (uint256 j = 0; j < values.length; ++j) {
        uint256 poolId = values[j];
        unchecked {
          pools[poolId].numStakes--;
        }
        delete stakes[nftIds[i]][poolId];
      }
      delete positions[nftIds[i]];

      if (!_emergencyEnabled) {
        require(depositNFTs[sender].remove(nftIds[i]), 'Fail to remove depositNFTs');
        for (uint256 j = 0; j < values.length; ++j) {
          uint256 poolId = values[j];
          require(joinedPools[nftIds[i]].remove(poolId), 'Fail to remove joinedPools');
        }
      }

      nft.transferFrom(address(this), sender, nftIds[i]);
      emit EmergencyWithdraw(sender, nftIds[i]);
    }
  }

  /**
   * @dev Emergency withdraw funds from contract, only admin can call this function
   * @param rewards List of ERC20 tokens
   * @param amounts List of amounts to be withdrawn
   */
  function emergencyWithdrawForOwner(address[] calldata rewards, uint256[] calldata amounts)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
    checkLength(rewards.length, amounts.length)
  {
    for (uint256 i = 0; i < rewards.length; ++i) {
      if (rewards[i] == address(0)) {
        (bool success, ) = payable(msg.sender).call{value: amounts[i]}('');
        require(success, 'transfer reward token failed');
        emit EmergencyWithdrawForOwner(rewards[i], amounts[i]);
      } else {
        IERC20Metadata(rewards[i]).safeTransfer(msg.sender, amounts[i]);
        emit EmergencyWithdrawForOwner(rewards[i], amounts[i]);
      }
    }
  }

  /**
   * @dev Join pools
   * @param pId pool id to join
   * @param nftIds nfts to join
   * @param liqs list liquidity value to join each nft
   *
   */
  function join(
    uint256 pId,
    uint256[] calldata nftIds,
    uint256[] calldata liqs
  ) external nonReentrant checkLength(nftIds.length, liqs.length) {
    require(numPools > pId, 'Pool not exists');
    LMPoolInfo storage pool = pools[pId];
    require(pool.startTime <= _getBlockTime() && _getBlockTime() < pool.endTime, 'Invalid time');
    for (uint256 i = 0; i < nftIds.length; ++i) {
      require(positions[nftIds[i]].owner == msg.sender, 'Not owner');
      positions[nftIds[i]].liquidity = getLiq(address(nft), nftIds[i]);
      StakeInfo storage stake = stakes[nftIds[i]][pId];
      if (stake.liquidity == 0) {
        _join(nftIds[i], pId, liqs[i], pool);
      } else {
        _sync(nftIds[i], pId, liqs[i], pool);
      }
    }
  }

  /**
   * @dev Exit from pools
   * @param pId pool ids to exit
   * @param nftIds list nfts id
   * @param liqs list liquidity value to exit from each nft
   *
   */
  function exit(
    uint256 pId,
    uint256[] calldata nftIds,
    uint256[] calldata liqs
  ) external nonReentrant checkLength(nftIds.length, liqs.length) {
    require(numPools > pId, 'Pool not exists');
    for (uint256 i = 0; i < nftIds.length; ++i) {
      _exit(nftIds[i], pId, liqs[i]);
    }
  }

  /**
   * @dev Claim rewards for a list of pools for a list of nft positions
   * @param nftIds List of NFT ids to harvest
   * @param datas List of pool ids to harvest for each nftId, encoded into bytes
   */
  function harvestMultiplePools(uint256[] calldata nftIds, bytes[] calldata datas)
    external
    nonReentrant
    checkLength(nftIds.length, datas.length)
  {
    for (uint256 i; i < nftIds.length; ++i) {
      require(positions[nftIds[i]].owner == msg.sender, 'harvest: not owner');
      HarvestData memory data = abi.decode(datas[i], (HarvestData));
      for (uint256 j; j < data.pIds.length; ++j) {
        _harvest(nftIds[i], data.pIds[j]);
      }
    }
  }

  /**
   * GETTER FUNCTION *****************************
   */
  function poolLength() external view returns (uint256) {
    return numPools;
  }

  function getJoinedPools(uint256 nftId) external view returns (uint256[] memory poolIds) {
    uint256 length = joinedPools[nftId].length();
    poolIds = new uint256[](length);
    for (uint256 i = 0; i < length; ++i) {
      poolIds[i] = joinedPools[nftId].at(i);
    }
  }

  function getJoinedPoolsInRange(
    uint256 nftId,
    uint256 fromIndex,
    uint256 toIndex
  ) external view returns (uint256[] memory poolIds) {
    require(fromIndex <= toIndex, 'fromIndex > toIndex');
    require(toIndex < joinedPools[nftId].length(), 'toIndex >= length');
    poolIds = new uint256[](toIndex - fromIndex + 1);
    for (uint256 index = fromIndex; index <= toIndex; ++index) {
      poolIds[index - fromIndex] = joinedPools[nftId].at(index);
    }
  }

  function getUserInfo(uint256 nftId, uint256 pId)
    external
    view
    returns (
      uint256 liquidity,
      uint256[] memory rewardPending,
      uint256[] memory rewardLast
    )
  {
    LMPoolInfo storage pool = pools[pId];
    StakeInfo storage stake = stakes[nftId][pId];

    require(stake.liquidity > 0, 'getUserInfo: not joined yet');

    rewardPending = new uint256[](pool.rewards.length);
    rewardLast = new uint256[](pool.rewards.length);

    RewardCalculationData memory data = getRewardCalculationData(nftId, pId);
    for (uint256 i = 0; i < pool.rewards.length; ++i) {
      uint256 rewardHarvest = _calculateRewardHarvest(
        stake.liquidity,
        pool.rewards[i].rewardUnclaimed,
        data.totalSecondsUnclaimed,
        data.secondsPerLiquidity
      );
      uint256 rewardCollected = _calculateRewardCollected(
        stake.rewardHarvested[i] + rewardHarvest,
        data.vestingVolume,
        stake.rewardLast[i]
      );
      rewardPending[i] = stake.rewardPending[i] + rewardCollected;
      rewardLast[i] = stake.rewardLast[i];
    }
    liquidity = stake.liquidity;
  }

  function getPoolInfo(uint256 pId)
    external
    view
    returns (
      address poolAddress,
      uint32 startTime,
      uint32 endTime,
      uint32 vestingDuration,
      uint256 totalSecondsClaimed,
      uint256 feeTarget,
      uint256 numStakes,
      //index reward => reward data
      address[] memory rewardTokens,
      uint256[] memory rewardUnclaimeds
    )
  {
    LMPoolInfo storage pool = pools[pId];

    poolAddress = pool.poolAddress;
    startTime = pool.startTime;
    endTime = pool.endTime;
    vestingDuration = pool.vestingDuration;
    totalSecondsClaimed = pool.totalSecondsClaimed;
    feeTarget = pool.feeTarget;
    numStakes = pool.numStakes;

    uint256 length = pool.rewards.length;
    rewardTokens = new address[](length);
    rewardUnclaimeds = new uint256[](length);
    for (uint256 i = 0; i < length; ++i) {
      rewardTokens[i] = pool.rewards[i].rewardToken;
      rewardUnclaimeds[i] = pool.rewards[i].rewardUnclaimed;
    }
  }

  function getDepositedNFTs(address user) external view returns (uint256[] memory listNFTs) {
    listNFTs = depositNFTs[user].values();
  }

  /**
   * INTERNAL FUNCTIONS *************************
   */
  /**
   * @dev join pool first time
   * @param nftId NFT id to join
   * @param pId pool id to join
   * @param liq liquidity amount to join
   * @param pool LM pool
   */
  function _join(
    uint256 nftId,
    uint256 pId,
    uint256 liq,
    LMPoolInfo storage pool
  ) internal {
    PositionInfo storage position = positions[nftId];
    StakeInfo storage stake = stakes[nftId][pId];
    require(checkPool(pool.poolAddress, address(nft), nftId), 'join: invalid pool');
    require(liq != 0 && liq <= position.liquidity, 'join: invalid liq');

    stake.secondsPerLiquidityLast = getActiveTime(pool.poolAddress, address(nft), nftId);
    stake.rewardLast = new uint256[](pool.rewards.length);
    stake.rewardPending = new uint256[](pool.rewards.length);
    stake.rewardHarvested = new uint256[](pool.rewards.length);
    if (pool.feeTarget != 0) {
      stake.feeFirst = getSignedFee(address(nft), nftId);
    }
    stake.liquidity = liq;
    pool.numStakes++;

    require(joinedPools[nftId].add(pId), 'Fail to add joinedPools');

    emit Join(nftId, pId, liq);
  }

  /**
   * @dev Increase liquidity in pool
   * @param nftId NFT id to sync
   * @param pId pool id to sync
   * @param liq liquidity amount to increase
   * @param pool LM pool
   */
  function _sync(
    uint256 nftId,
    uint256 pId,
    uint256 liq,
    LMPoolInfo storage pool
  ) internal {
    PositionInfo storage position = positions[nftId];
    StakeInfo storage stake = stakes[nftId][pId];

    require(liq != 0 && liq + stake.liquidity <= position.liquidity, 'sync: invalid liq');

    RewardCalculationData memory data = getRewardCalculationData(nftId, pId);

    for (uint256 i = 0; i < pool.rewards.length; ++i) {
      uint256 rewardHarvest = _calculateRewardHarvest(
        stake.liquidity,
        pool.rewards[i].rewardUnclaimed,
        data.totalSecondsUnclaimed,
        data.secondsPerLiquidity
      );

      if (rewardHarvest != 0) {
        stake.rewardHarvested[i] += rewardHarvest;
        pool.rewards[i].rewardUnclaimed -= rewardHarvest;
      }

      uint256 rewardCollected = _calculateRewardCollected(
        stake.rewardHarvested[i],
        data.vestingVolume,
        stake.rewardLast[i]
      );

      if (rewardCollected != 0) {
        stake.rewardLast[i] += rewardCollected;
        stake.rewardPending[i] += rewardCollected;
      }
    }

    pool.totalSecondsClaimed += data.secondsClaim;
    stake.secondsPerLiquidityLast = data.secondsPerLiquidityNow;
    stake.feeFirst = _calculateFeeFirstAfterJoin(
      stake.feeFirst,
      data.feeNow,
      pool.feeTarget,
      stake.liquidity,
      liq,
      nftId
    );
    stake.liquidity += liq;
    emit SyncLiq(nftId, pId, liq);
  }

  /**
   * @dev Exit pool
   * @param nftId NFT id to exit
   * @param pId pool id to exit
   * @param liq liquidity amount to exit
   */
  function _exit(
    uint256 nftId,
    uint256 pId,
    uint256 liq
  ) internal {
    LMPoolInfo storage pool = pools[pId];
    PositionInfo storage position = positions[nftId];
    StakeInfo storage stake = stakes[nftId][pId];

    require(
      position.owner == msg.sender ||
        (_getBlockTime() > pool.endTime && hasRole(OPERATOR_ROLE, msg.sender)),
      'exit: not owner or pool not ended'
    );

    require(liq != 0 && liq <= stake.liquidity, 'exit: invalid liq');

    uint256 liquidityOld = stake.liquidity;
    uint256 liquidityNew = liquidityOld - liq;
    RewardCalculationData memory data = getRewardCalculationData(nftId, pId);

    pool.totalSecondsClaimed += data.secondsClaim;
    stake.secondsPerLiquidityLast = data.secondsPerLiquidityNow;
    stake.liquidity = liquidityNew;
    for (uint256 i = 0; i < pool.rewards.length; ++i) {
      uint256 rewardHarvest = _calculateRewardHarvest(
        liquidityOld,
        pool.rewards[i].rewardUnclaimed,
        data.totalSecondsUnclaimed,
        data.secondsPerLiquidity
      );

      if (rewardHarvest != 0) {
        stake.rewardHarvested[i] += rewardHarvest;
        pool.rewards[i].rewardUnclaimed -= rewardHarvest;
      }

      uint256 rewardCollected = _calculateRewardCollected(
        stake.rewardHarvested[i],
        data.vestingVolume,
        stake.rewardLast[i]
      );

      uint256 rewardPending = stake.rewardPending[i] + rewardCollected;
      if (rewardPending != 0) {
        if (rewardCollected != 0) {
          stake.rewardLast[i] += rewardCollected;
        }
        stake.rewardPending[i] = 0;
        _lockReward(
          IERC20Metadata(pool.rewards[i].rewardToken),
          position.owner,
          rewardPending,
          pool.vestingDuration
        );
      }
    }
    if (liquidityNew == 0) {
      delete stakes[nftId][pId];
      pool.numStakes--;

      require(joinedPools[nftId].remove(pId), 'Fail to remove joinedPools');
    }
    emit Exit(msg.sender, nftId, pId, liq);
  }

  /**
   * @dev Harvest reward
   * @param nftId NFT id to harvest
   * @param pId pool id to harvest
   */
  function _harvest(uint256 nftId, uint256 pId) internal {
    require(numPools > pId, 'Pool not exists');
    LMPoolInfo storage pool = pools[pId];
    PositionInfo storage position = positions[nftId];
    StakeInfo storage stake = stakes[nftId][pId];

    require(stake.liquidity > 0, 'harvest: not joined yet');

    RewardCalculationData memory data = getRewardCalculationData(nftId, pId);

    pool.totalSecondsClaimed += data.secondsClaim;
    stake.secondsPerLiquidityLast = data.secondsPerLiquidityNow;
    for (uint256 i = 0; i < pool.rewards.length; ++i) {
      uint256 rewardHarvest = _calculateRewardHarvest(
        stake.liquidity,
        pool.rewards[i].rewardUnclaimed,
        data.totalSecondsUnclaimed,
        data.secondsPerLiquidity
      );

      if (rewardHarvest != 0) {
        stake.rewardHarvested[i] += rewardHarvest;
        pool.rewards[i].rewardUnclaimed -= rewardHarvest;
      }

      uint256 rewardCollected = _calculateRewardCollected(
        stake.rewardHarvested[i],
        data.vestingVolume,
        stake.rewardLast[i]
      );

      uint256 rewardPending = stake.rewardPending[i] + rewardCollected;
      if (rewardPending != 0) {
        if (rewardCollected != 0) {
          stake.rewardLast[i] += rewardCollected;
        }
        stake.rewardPending[i] = 0;
        _lockReward(
          IERC20Metadata(pool.rewards[i].rewardToken),
          position.owner,
          rewardPending,
          pool.vestingDuration
        );
      }
    }
  }

  /**
   * @dev Send reward to rewardLocker contract
   */
  function _lockReward(
    IERC20Metadata token,
    address _account,
    uint256 _amount,
    uint32 _vestingDuration
  ) internal {
    uint256 value = token == IERC20Metadata(address(0)) ? _amount : 0;
    rewardLocker.lock{value: value}(address(token), _account, _amount, _vestingDuration);
    emit Harvest(_account, address(token), _amount);
  }

  /**
   * HELPER MATH FUNCTIONS *************************
   */
  function getRewardCalculationData(uint256 nftId, uint256 pId)
    public
    view
    returns (RewardCalculationData memory data)
  {
    LMPoolInfo storage pool = pools[pId];
    StakeInfo storage stake = stakes[nftId][pId];

    data.secondsPerLiquidityNow = getActiveTime(pool.poolAddress, address(nft), nftId);
    data.feeNow = getSignedFeePool(pool.poolAddress, address(nft), nftId);
    data.vestingVolume = _calculateVestingVolume(data.feeNow, stake.feeFirst, pool.feeTarget);
    data.totalSecondsUnclaimed = _calculateSecondsUnclaimed(
      pool.startTime,
      pool.endTime,
      pool.totalSecondsClaimed
    );
    unchecked {
      data.secondsPerLiquidity = data.secondsPerLiquidityNow - stake.secondsPerLiquidityLast;
    }
    data.secondsClaim = stake.liquidity * data.secondsPerLiquidity;
  }

  /**
   * @dev feeFirst = (liq * max(feeNow - feeTarget, feeFirst) + liqAdd * feeNow) / liqNew
   */
  function _calculateFeeFirstAfterJoin(
    int256 feeFirst,
    int256 feeNow,
    uint256 feeTarget,
    uint256 liquidity,
    uint256 liquidityAdd,
    uint256 nftId
  ) internal view returns (int256) {
    if (feeTarget == 0) {
      return 0;
    }
    int256 feeFirstCurrent = feeNow - int256(feeTarget) < feeFirst
      ? feeFirst
      : feeNow - int256(feeTarget);
    int256 numerator = int256(liquidity) *
      feeFirstCurrent +
      int256(liquidityAdd) *
      getSignedFee(address(nft), nftId);
    int256 denominator = int256(liquidity + liquidityAdd);
    return numerator / denominator;
  }

  /**
   * @dev vesting = min((feeNow - feeFirst) / feeTarget, 1)
   */
  function _calculateVestingVolume(
    int256 feeNow,
    int256 feeFirst,
    uint256 feeTarget
  ) internal pure returns (uint256) {
    if (feeTarget == 0) {
      return PRECISION;
    }
    uint256 feeInside = uint256(feeNow - feeFirst);
    return KSMath.min((feeInside * PRECISION) / feeTarget, PRECISION);
  }

  /**
   * @dev secondsUnclaimed = (max(currentTime, endTime) - startTime) - secondsClaimed
   */
  function _calculateSecondsUnclaimed(
    uint256 startTime,
    uint256 endTime,
    uint256 totalSecondsClaimed
  ) internal view returns (uint256) {
    uint256 totalSeconds = KSMath.max(_getBlockTime(), endTime) - startTime;
    uint256 totalSecondsScaled = totalSeconds * (1 << 96);
    return totalSecondsScaled > totalSecondsClaimed ? totalSecondsScaled - totalSecondsClaimed : 0;
  }

  /**
   * @dev rewardHarvested = L * rewardRate * secondsPerLiquidity
   */
  function _calculateRewardHarvest(
    uint256 liquidity,
    uint256 rewardUnclaimed,
    uint256 totalSecondsUnclaimed,
    uint256 secondsPerLiquidity
  ) internal pure returns (uint256) {
    return (liquidity * rewardUnclaimed * secondsPerLiquidity) / totalSecondsUnclaimed;
  }

  /**
   * @dev rewardCollected = Max(rewardHarvested * vestingVolume - rewardLast, 0);
   */
  function _calculateRewardCollected(
    uint256 rewardHarvested,
    uint256 vestingVolume,
    uint256 rewardLast
  ) internal pure returns (uint256) {
    uint256 rewardNow = (rewardHarvested * vestingVolume) / PRECISION;
    return rewardNow > rewardLast ? rewardNow - rewardLast : 0;
  }

  function _getBlockTime() internal view virtual returns (uint32) {
    return uint32(block.timestamp);
  }
}

File 2 of 25 : LMHelper.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import '../interfaces/liquidityMining/IBasePositionManager.sol';
import '../interfaces/liquidityMining/IPoolStorage.sol';
import {MathConstants as C} from '../libraries/MathConstants.sol';
import {FullMath} from '../libraries/FullMath.sol';
import {ReinvestmentMath} from '../libraries/ReinvestmentMath.sol';

abstract contract LMHelper {
  function checkPool(
    address pAddress,
    address nftContract,
    uint256 nftId
  ) public view returns (bool) {
    IBasePositionManager.Position memory pData = _getPositionFromNFT(nftContract, nftId);
    return IBasePositionManager(nftContract).addressToPoolId(pAddress) == pData.poolId;
  }

  /**
   * @dev Get fee
   * use virtual to be overrided to mock data for fuzz tests
   */
  function getFee(address nftContract, uint256 nftId) public view virtual returns (uint256) {
    IBasePositionManager.Position memory pData = _getPositionFromNFT(nftContract, nftId);
    return pData.feeGrowthInsideLast;
  }

  /**
   * @dev Get fee
   * use virtual to be overrided to mock data for fuzz tests
   *
   */
  function getFeePool(
    address poolAddress,
    address nftContract,
    uint256 nftId
  ) public view virtual returns (uint256 feeGrowthInside) {
    IBasePositionManager.Position memory position = _getPositionFromNFT(nftContract, nftId);
    (, , uint256 lowerValue, ) = IPoolStorage(poolAddress).ticks(position.tickLower);
    (, , uint256 upperValue, ) = IPoolStorage(poolAddress).ticks(position.tickUpper);
    (, int24 currentTick, , ) = IPoolStorage(poolAddress).getPoolState();
    uint256 feeGrowthGlobal = IPoolStorage(poolAddress).getFeeGrowthGlobal();

    {
      (uint128 baseL, uint128 reinvestL, uint128 reinvestLLast) = IPoolStorage(poolAddress)
        .getLiquidityState();
      uint256 rTotalSupply = IERC20(poolAddress).totalSupply();
      // logic ported from Pool._syncFeeGrowth()
      uint256 rMintQty = ReinvestmentMath.calcrMintQty(
        uint256(reinvestL),
        uint256(reinvestLLast),
        baseL,
        rTotalSupply
      );

      if (rMintQty != 0) {
        // fetch governmentFeeUnits
        (, uint24 governmentFeeUnits) = IPoolStorage(poolAddress).factory().feeConfiguration();
        unchecked {
          if (governmentFeeUnits != 0) {
            uint256 rGovtQty = (rMintQty * governmentFeeUnits) / C.FEE_UNITS;
            rMintQty -= rGovtQty;
          }
          feeGrowthGlobal += FullMath.mulDivFloor(rMintQty, C.TWO_POW_96, baseL);
        }
      }
    }
    unchecked {
      if (currentTick < position.tickLower) {
        feeGrowthInside = lowerValue - upperValue;
      } else if (currentTick >= position.tickUpper) {
        feeGrowthInside = upperValue - lowerValue;
      } else {
        feeGrowthInside = feeGrowthGlobal - (lowerValue + upperValue);
      }
    }
  }

  /// @dev use virtual to be overrided to mock data for fuzz tests
  function getActiveTime(
    address pAddr,
    address nftContract,
    uint256 nftId
  ) public view virtual returns (uint128) {
    IBasePositionManager.Position memory pData = _getPositionFromNFT(nftContract, nftId);
    return IPoolStorage(pAddr).getSecondsPerLiquidityInside(pData.tickLower, pData.tickUpper);
  }

  function getSignedFee(address nftContract, uint256 nftId) public view returns (int256) {
    uint256 feeGrowthInsideLast = getFee(nftContract, nftId);
    return int256(feeGrowthInsideLast);
  }

  function getSignedFeePool(
    address poolAddress,
    address nftContract,
    uint256 nftId
  ) public view returns (int256) {
    uint256 feeGrowthInside = getFeePool(poolAddress, nftContract, nftId);
    return int256(feeGrowthInside);
  }

  function getLiq(address nftContract, uint256 nftId) public view returns (uint128) {
    IBasePositionManager.Position memory pData = _getPositionFromNFT(nftContract, nftId);
    return pData.liquidity;
  }

  function _getPositionFromNFT(address nftContract, uint256 nftId)
    internal
    view
    returns (IBasePositionManager.Position memory)
  {
    (IBasePositionManager.Position memory pData, ) = IBasePositionManager(nftContract).positions(
      nftId
    );
    return pData;
  }
}

File 3 of 25 : KSMath.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

library KSMath {
  function max(uint256 a, uint256 b) internal pure returns (uint256) {
    return a >= b ? a : b;
  }

  function min(uint256 a, uint256 b) internal pure returns (uint256) {
    return a >= b ? b : a;
  }
}

File 4 of 25 : IKyberSwapElasticLM.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {IKyberSwapElasticLMEvents} from './IKyberSwapElasticLMEvents.sol';
import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';

interface IKyberSwapElasticLM is IKyberSwapElasticLMEvents {
  struct RewardData {
    address rewardToken;
    uint256 rewardUnclaimed;
  }

  struct LMPoolInfo {
    address poolAddress;
    uint32 startTime;
    uint32 endTime;
    uint32 vestingDuration;
    uint256 totalSecondsClaimed; // scaled by (1 << 96)
    RewardData[] rewards;
    uint256 feeTarget;
    uint256 numStakes;
  }

  struct PositionInfo {
    address owner;
    uint256 liquidity;
  }

  struct StakeInfo {
    uint128 secondsPerLiquidityLast;
    uint256[] rewardLast;
    uint256[] rewardPending;
    uint256[] rewardHarvested;
    int256 feeFirst;
    uint256 liquidity;
  }

  // input data in harvestMultiplePools function
  struct HarvestData {
    uint256[] pIds;
  }

  // avoid stack too deep error
  struct RewardCalculationData {
    uint128 secondsPerLiquidityNow;
    int256 feeNow;
    uint256 vestingVolume;
    uint256 totalSecondsUnclaimed;
    uint256 secondsPerLiquidity;
    uint256 secondsClaim; // scaled by (1 << 96)
  }

  /**
   * @dev Add new pool to LM
   * @param poolAddr pool address
   * @param startTime start time of liquidity mining
   * @param endTime end time of liquidity mining
   * @param vestingDuration time locking in reward locker
   * @param rewardTokens reward token list for pool
   * @param rewardAmounts reward amount of list token
   * @param feeTarget fee target for pool
   *
   */
  function addPool(
    address poolAddr,
    uint32 startTime,
    uint32 endTime,
    uint32 vestingDuration,
    address[] calldata rewardTokens,
    uint256[] calldata rewardAmounts,
    uint256 feeTarget
  ) external;

  /**
   * @dev Renew a pool to start another LM program
   * @param pId pool id to update
   * @param startTime start time of liquidity mining
   * @param endTime end time of liquidity mining
   * @param vestingDuration time locking in reward locker
   * @param rewardAmounts reward amount of list token
   * @param feeTarget fee target for pool
   *
   */
  function renewPool(
    uint256 pId,
    uint32 startTime,
    uint32 endTime,
    uint32 vestingDuration,
    uint256[] calldata rewardAmounts,
    uint256 feeTarget
  ) external;

  /**
   * @dev Deposit NFT
   * @param nftIds list nft id
   *
   */
  function deposit(uint256[] calldata nftIds) external;

  /**
   * @dev Withdraw NFT, must exit all pool before call.
   * @param nftIds list nft id
   *
   */
  function withdraw(uint256[] calldata nftIds) external;

  /**
   * @dev Join pools
   * @param pId pool id to join
   * @param nftIds nfts to join
   * @param liqs list liquidity value to join each nft
   *
   */
  function join(
    uint256 pId,
    uint256[] calldata nftIds,
    uint256[] calldata liqs
  ) external;

  /**
   * @dev Exit from pools
   * @param pId pool ids to exit
   * @param nftIds list nfts id
   * @param liqs list liquidity value to exit from each nft
   *
   */
  function exit(
    uint256 pId,
    uint256[] calldata nftIds,
    uint256[] calldata liqs
  ) external;

  /**
   * @dev Operator only. Call to withdraw all reward from list pools.
   * @param rewards list reward address erc20 token
   * @param amounts amount to withdraw
   *
   */
  function emergencyWithdrawForOwner(address[] calldata rewards, uint256[] calldata amounts)
    external;

  /**
   * @dev Withdraw NFT, can call any time, reward will be reset. Must enable this func by operator
   * @param pIds list pool to withdraw
   *
   */
  function emergencyWithdraw(uint256[] calldata pIds) external;

  function nft() external view returns (IERC721);

  function poolLength() external view returns (uint256);

  function getUserInfo(uint256 nftId, uint256 pId)
    external
    view
    returns (
      uint256 liquidity,
      uint256[] memory rewardPending,
      uint256[] memory rewardLast
    );

  function getPoolInfo(uint256 pId)
    external
    view
    returns (
      address poolAddress,
      uint32 startTime,
      uint32 endTime,
      uint32 vestingDuration,
      uint256 totalSecondsClaimed,
      uint256 feeTarget,
      uint256 numStakes,
      //index reward => reward data
      address[] memory rewardTokens,
      uint256[] memory rewardUnclaimeds
    );

  function getDepositedNFTs(address user) external view returns (uint256[] memory listNFTs);

  function getRewardCalculationData(uint256 nftId, uint256 pId)
    external
    view
    returns (RewardCalculationData memory data);
}

File 5 of 25 : IKyberRewardLockerV2.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.9;

interface IKyberRewardLockerV2 {
  /**
   * @dev queue a vesting schedule starting from now
   */
  function lock(
    address token,
    address account,
    uint256 amount,
    uint32 vestingDuration
  ) external payable;

  /**
   * @dev queue a vesting schedule
   */
  function lockWithStartTime(
    address token,
    address account,
    uint256 quantity,
    uint256 startTime,
    uint32 vestingDuration
  ) external payable;
}

File 6 of 25 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}

File 7 of 25 : 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 8 of 25 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 9 of 25 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

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

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

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

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

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

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

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

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

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

            return true;
        } else {
            return false;
        }
    }

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

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

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

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

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

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

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

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

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

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

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

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

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

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

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

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

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

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

        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

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

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

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

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

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

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

        assembly {
            result := store
        }

        return result;
    }
}

File 10 of 25 : AccessControl.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

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

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

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

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

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

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

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

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

        _revokeRole(role, account);
    }

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

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

    function _grantRole(bytes32 role, address account) private {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    function _revokeRole(bytes32 role, address account) private {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 11 of 25 : 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 12 of 25 : IBasePositionManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

interface IBasePositionManager {
  struct Position {
    // the nonce for permits
    uint96 nonce;
    // the address that is approved for spending this token
    address operator;
    // the ID of the pool with which this token is connected
    uint80 poolId;
    // the tick range of the position
    int24 tickLower;
    int24 tickUpper;
    // the liquidity of the position
    uint128 liquidity;
    // the current rToken that the position owed
    uint256 rTokenOwed;
    // fee growth per unit of liquidity as of the last update to liquidity
    uint256 feeGrowthInsideLast;
  }

  struct PoolInfo {
    address token0;
    uint16 fee;
    address token1;
  }

  function positions(uint256 tokenId)
    external
    view
    returns (Position memory pos, PoolInfo memory info);

  function addressToPoolId(address pool) external view returns (uint80);
}

File 13 of 25 : IPoolStorage.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity >=0.8.0;

import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';

import {IFactory} from './IFactory.sol';

interface IPoolStorage {
  struct PoolData {
    uint160 sqrtP;
    int24 nearestCurrentTick;
    int24 currentTick;
    bool locked;
    uint128 baseL;
    uint128 reinvestL;
    uint128 reinvestLLast;
    uint256 feeGrowthGlobal;
    uint128 secondsPerLiquidityGlobal;
    uint32 secondsPerLiquidityUpdateTime;
  }

  // data stored for each initialized individual tick
  struct TickData {
    // gross liquidity of all positions in tick
    uint128 liquidityGross;
    // liquidity quantity to be added | removed when tick is crossed up | down
    int128 liquidityNet;
    // fee growth per unit of liquidity on the other side of this tick (relative to current tick)
    // only has relative meaning, not absolute — the value depends on when the tick is initialized
    uint256 feeGrowthOutside;
    // seconds spent on the other side of this tick (relative to current tick)
    // only has relative meaning, not absolute — the value depends on when the tick is initialized
    uint128 secondsPerLiquidityOutside;
  }

  /// @notice The contract that deployed the pool, which must adhere to the IFactory interface
  /// @return The contract address
  function factory() external view returns (IFactory);

  /// @notice The first of the two tokens of the pool, sorted by address
  /// @return The token contract address
  function token0() external view returns (IERC20);

  /// @notice The second of the two tokens of the pool, sorted by address
  /// @return The token contract address
  function token1() external view returns (IERC20);

  /// @notice The fee to be charged for a swap in basis points
  /// @return The swap fee in basis points
  function swapFeeBps() external view returns (uint16);

  /// @notice The pool tick distance
  /// @dev Ticks can only be initialized and used at multiples of this value
  /// It remains an int24 to avoid casting even though it is >= 1.
  /// e.g: a tickDistance of 5 means ticks can be initialized every 5th tick, i.e., ..., -10, -5, 0, 5, 10, ...
  /// @return The tick distance
  function tickDistance() external view returns (int24);

  /// @notice Maximum gross liquidity that an initialized tick can have
  /// @dev This is to prevent overflow the pool's active base liquidity (uint128)
  /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
  /// @return The max amount of liquidity per tick
  function maxTickLiquidity() external view returns (uint128);

  /// @notice Look up information about a specific tick in the pool
  /// @param tick The tick to look up
  /// @return liquidityGross total liquidity amount from positions that uses this tick as a lower or upper tick
  /// liquidityNet how much liquidity changes when the pool tick crosses above the tick
  /// feeGrowthOutside the fee growth on the other side of the tick relative to the current tick
  /// secondsPerLiquidityOutside the seconds spent on the other side of the tick relative to the current tick
  function ticks(int24 tick)
    external
    view
    returns (
      uint128 liquidityGross,
      int128 liquidityNet,
      uint256 feeGrowthOutside,
      uint128 secondsPerLiquidityOutside
    );

  /// @notice Returns the previous and next initialized ticks of a specific tick
  /// @dev If specified tick is uninitialized, the returned values are zero.
  /// @param tick The tick to look up
  function initializedTicks(int24 tick) external view returns (int24 previous, int24 next);

  /// @notice Returns the information about a position by the position's key
  /// @return liquidity the liquidity quantity of the position
  /// @return feeGrowthInsideLast fee growth inside the tick range as of the last mint / burn action performed
  function getPositions(
    address owner,
    int24 tickLower,
    int24 tickUpper
  ) external view returns (uint128 liquidity, uint256 feeGrowthInsideLast);

  /// @notice Fetches the pool's prices, ticks and lock status
  /// @return sqrtP sqrt of current price: sqrt(token1/token0)
  /// @return currentTick pool's current tick
  /// @return nearestCurrentTick pool's nearest initialized tick that is <= currentTick
  /// @return locked true if pool is locked, false otherwise
  function getPoolState()
    external
    view
    returns (
      uint160 sqrtP,
      int24 currentTick,
      int24 nearestCurrentTick,
      bool locked
    );

  /// @notice Fetches the pool's liquidity values
  /// @return baseL pool's base liquidity without reinvest liqudity
  /// @return reinvestL the liquidity is reinvested into the pool
  /// @return reinvestLLast last cached value of reinvestL, used for calculating reinvestment token qty
  function getLiquidityState()
    external
    view
    returns (
      uint128 baseL,
      uint128 reinvestL,
      uint128 reinvestLLast
    );

  /// @return feeGrowthGlobal All-time fee growth per unit of liquidity of the pool
  function getFeeGrowthGlobal() external view returns (uint256);

  /// @return secondsPerLiquidityGlobal All-time seconds per unit of liquidity of the pool
  /// @return lastUpdateTime The timestamp in which secondsPerLiquidityGlobal was last updated
  function getSecondsPerLiquidityData()
    external
    view
    returns (uint128 secondsPerLiquidityGlobal, uint32 lastUpdateTime);

  /// @notice Calculates and returns the active time per unit of liquidity until current block.timestamp
  /// @param tickLower The lower tick (of a position)
  /// @param tickUpper The upper tick (of a position)
  /// @return secondsPerLiquidityInside active time (multiplied by 2^96)
  /// between the 2 ticks, per unit of liquidity.
  function getSecondsPerLiquidityInside(int24 tickLower, int24 tickUpper)
    external
    view
    returns (uint128 secondsPerLiquidityInside);
}

File 14 of 25 : MathConstants.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity >=0.8.0;

/// @title Contains constants needed for math libraries
library MathConstants {
  uint256 internal constant TWO_POW_96 = 2**96;
  uint128 internal constant MIN_LIQUIDITY = 100_000;
  uint24 internal constant FEE_UNITS = 100_000;
  uint8 internal constant RES_96 = 96;
}

File 15 of 25 : FullMath.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
/// @dev Code has been modified to be compatible with sol 0.8
library FullMath {
  /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
  /// @param a The multiplicand
  /// @param b The multiplier
  /// @param denominator The divisor
  /// @return result The 256-bit result
  /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
  function mulDivFloor(
    uint256 a,
    uint256 b,
    uint256 denominator
  ) internal pure returns (uint256 result) {
    // 512-bit multiply [prod1 prod0] = a * b
    // Compute the product mod 2**256 and mod 2**256 - 1
    // then use the Chinese Remainder Theorem to reconstruct
    // the 512 bit result. The result is stored in two 256
    // variables such that product = prod1 * 2**256 + prod0
    uint256 prod0; // Least significant 256 bits of the product
    uint256 prod1; // Most significant 256 bits of the product
    assembly {
      let mm := mulmod(a, b, not(0))
      prod0 := mul(a, b)
      prod1 := sub(sub(mm, prod0), lt(mm, prod0))
    }

    // Handle non-overflow cases, 256 by 256 division
    if (prod1 == 0) {
      require(denominator > 0, '0 denom');
      assembly {
        result := div(prod0, denominator)
      }
      return result;
    }

    // Make sure the result is less than 2**256.
    // Also prevents denominator == 0
    require(denominator > prod1, 'denom <= prod1');

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

    // Make division exact by subtracting the remainder from [prod1 prod0]
    // Compute remainder using mulmod
    uint256 remainder;
    assembly {
      remainder := mulmod(a, b, denominator)
    }
    // Subtract 256 bit number from 512 bit number
    assembly {
      prod1 := sub(prod1, gt(remainder, prod0))
      prod0 := sub(prod0, remainder)
    }

    // Factor powers of two out of denominator
    // Compute largest power of two divisor of denominator.
    // Always >= 1.
    uint256 twos = denominator & (~denominator + 1);
    // Divide denominator by power of two
    assembly {
      denominator := div(denominator, twos)
    }

    // Divide [prod1 prod0] by the factors of two
    assembly {
      prod0 := div(prod0, twos)
    }
    // Shift in bits from prod1 into prod0. For this we need
    // to flip `twos` such that it is 2**256 / twos.
    // If twos is zero, then it becomes one
    assembly {
      twos := add(div(sub(0, twos), twos), 1)
    }
    unchecked {
      prod0 |= prod1 * twos;

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

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

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

  /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
  /// @param a The multiplicand
  /// @param b The multiplier
  /// @param denominator The divisor
  /// @return result The 256-bit result
  function mulDivCeiling(
    uint256 a,
    uint256 b,
    uint256 denominator
  ) internal pure returns (uint256 result) {
    result = mulDivFloor(a, b, denominator);
    if (mulmod(a, b, denominator) > 0) {
      result++;
    }
  }
}

File 16 of 25 : ReinvestmentMath.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity >=0.8.0;

import {FullMath} from './FullMath.sol';

/// @title Contains helper function to calculate the number of reinvestment tokens to be minted
library ReinvestmentMath {
  /// @dev calculate the mint amount with given reinvestL, reinvestLLast, baseL and rTotalSupply
  /// contribution of lp to the increment is calculated by the proportion of baseL with reinvestL + baseL
  /// then rMintQty is calculated by mutiplying this with the liquidity per reinvestment token
  /// rMintQty = rTotalSupply * (reinvestL - reinvestLLast) / reinvestLLast * baseL / (baseL + reinvestL)
  function calcrMintQty(
    uint256 reinvestL,
    uint256 reinvestLLast,
    uint128 baseL,
    uint256 rTotalSupply
  ) internal pure returns (uint256 rMintQty) {
    uint256 lpContribution = FullMath.mulDivFloor(
      baseL,
      reinvestL - reinvestLLast,
      baseL + reinvestL
    );
    rMintQty = FullMath.mulDivFloor(rTotalSupply, lpContribution, reinvestLLast);
  }
}

File 17 of 25 : 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 18 of 25 : IFactory.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity >=0.8.0;

/// @title KyberSwap v2 factory
/// @notice Deploys KyberSwap v2 pools and manages control over government fees
interface IFactory {
  /// @notice Emitted when a pool is created
  /// @param token0 First pool token by address sort order
  /// @param token1 Second pool token by address sort order
  /// @param swapFeeBps Fee to be collected upon every swap in the pool, in basis points
  /// @param tickDistance Minimum number of ticks between initialized ticks
  /// @param pool The address of the created pool
  event PoolCreated(
    address indexed token0,
    address indexed token1,
    uint16 indexed swapFeeBps,
    int24 tickDistance,
    address pool
  );

  /// @notice Emitted when a new fee is enabled for pool creation via the factory
  /// @param swapFeeBps Fee to be collected upon every swap in the pool, in basis points
  /// @param tickDistance Minimum number of ticks between initialized ticks for pools created with the given fee
  event SwapFeeEnabled(uint16 indexed swapFeeBps, int24 indexed tickDistance);

  /// @notice Emitted when vesting period changes
  /// @param vestingPeriod The maximum time duration for which LP fees
  /// are proportionally burnt upon LP removals
  event VestingPeriodUpdated(uint32 vestingPeriod);

  /// @notice Emitted when configMaster changes
  /// @param oldConfigMaster configMaster before the update
  /// @param newConfigMaster configMaster after the update
  event ConfigMasterUpdated(address oldConfigMaster, address newConfigMaster);

  /// @notice Emitted when fee configuration changes
  /// @param feeTo Recipient of government fees
  /// @param governmentFeeBps Fee amount, in basis points,
  /// to be collected out of the fee charged for a pool swap
  event FeeConfigurationUpdated(address feeTo, uint16 governmentFeeBps);

  /// @notice Emitted when whitelist feature is enabled
  event WhitelistEnabled();

  /// @notice Emitted when whitelist feature is disabled
  event WhitelistDisabled();

  /// @notice Returns the maximum time duration for which LP fees
  /// are proportionally burnt upon LP removals
  function vestingPeriod() external view returns (uint32);

  /// @notice Returns the tick distance for a specified fee.
  /// @dev Once added, cannot be updated or removed.
  /// @param swapFeeBps Swap fee, in basis points.
  /// @return The tick distance. Returns 0 if fee has not been added.
  function feeAmountTickDistance(uint16 swapFeeBps) external view returns (int24);

  /// @notice Returns the address which can update the fee configuration
  function configMaster() external view returns (address);

  /// @notice Returns the keccak256 hash of the Pool creation code
  /// This is used for pre-computation of pool addresses
  function poolInitHash() external view returns (bytes32);

  /// @notice Fetches the recipient of government fees
  /// and current government fee charged in basis points
  function feeConfiguration() external view returns (address _feeTo, uint16 _governmentFeeBps);

  /// @notice Returns the status of whitelisting feature of NFT managers
  /// If true, anyone can mint liquidity tokens
  /// Otherwise, only whitelisted NFT manager(s) are allowed to mint liquidity tokens
  function whitelistDisabled() external view returns (bool);

  //// @notice Returns all whitelisted NFT managers
  /// If the whitelisting feature is turned on,
  /// only whitelisted NFT manager(s) are allowed to mint liquidity tokens
  function getWhitelistedNFTManagers() external view returns (address[] memory);

  /// @notice Checks if sender is a whitelisted NFT manager
  /// If the whitelisting feature is turned on,
  /// only whitelisted NFT manager(s) are allowed to mint liquidity tokens
  /// @param sender address to be checked
  /// @return true if sender is a whistelisted NFT manager, false otherwise
  function isWhitelistedNFTManager(address sender) external view returns (bool);

  /// @notice Returns the pool address for a given pair of tokens and a swap fee
  /// @dev Token order does not matter
  /// @param tokenA Contract address of either token0 or token1
  /// @param tokenB Contract address of the other token
  /// @param swapFeeBps Fee to be collected upon every swap in the pool, in basis points
  /// @return pool The pool address. Returns null address if it does not exist
  function getPool(
    address tokenA,
    address tokenB,
    uint16 swapFeeBps
  ) external view returns (address pool);

  /// @notice Fetch parameters to be used for pool creation
  /// @dev Called by the pool constructor to fetch the parameters of the pool
  /// @return factory The factory address
  /// @return token0 First pool token by address sort order
  /// @return token1 Second pool token by address sort order
  /// @return swapFeeBps Fee to be collected upon every swap in the pool, in basis points
  /// @return tickDistance Minimum number of ticks between initialized ticks
  function parameters()
    external
    view
    returns (
      address factory,
      address token0,
      address token1,
      uint16 swapFeeBps,
      int24 tickDistance
    );

  /// @notice Creates a pool for the given two tokens and fee
  /// @param tokenA One of the two tokens in the desired pool
  /// @param tokenB The other of the two tokens in the desired pool
  /// @param swapFeeBps Desired swap fee for the pool, in basis points
  /// @dev Token order does not matter. tickDistance is determined from the fee.
  /// Call will revert under any of these conditions:
  ///     1) pool already exists
  ///     2) invalid swap fee
  ///     3) invalid token arguments
  /// @return pool The address of the newly created pool
  function createPool(
    address tokenA,
    address tokenB,
    uint16 swapFeeBps
  ) external returns (address pool);

  /// @notice Enables a fee amount with the given tickDistance
  /// @dev Fee amounts may never be removed once enabled
  /// @param swapFeeBps The fee amount to enable, in basis points
  /// @param tickDistance The distance between ticks to be enforced for all pools created with the given fee amount
  function enableSwapFee(uint16 swapFeeBps, int24 tickDistance) external;

  /// @notice Updates the address which can update the fee configuration
  /// @dev Must be called by the current configMaster
  function updateConfigMaster(address) external;

  /// @notice Updates the vesting period
  /// @dev Must be called by the current configMaster
  function updateVestingPeriod(uint32) external;

  /// @notice Updates the address receiving government fees and fee quantity
  /// @dev Only configMaster is able to perform the update
  /// @param feeTo Address to receive government fees collected from pools
  /// @param governmentFeeBps Fee amount, in basis points,
  /// to be collected out of the fee charged for a pool swap
  function updateFeeConfiguration(address feeTo, uint16 governmentFeeBps) external;

  /// @notice Enables the whitelisting feature
  /// @dev Only configMaster is able to perform the update
  function enableWhitelist() external;

  /// @notice Disables the whitelisting feature
  /// @dev Only configMaster is able to perform the update
  function disableWhitelist() external;
}

File 19 of 25 : IKyberSwapElasticLMEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

interface IKyberSwapElasticLMEvents {
  event AddPool(
    uint256 indexed pId,
    address poolAddress,
    uint32 startTime,
    uint32 endTime,
    uint32 vestingDuration,
    uint256 feeTarget
  );

  event RenewPool(
    uint256 indexed pid,
    uint32 startTime,
    uint32 endTime,
    uint32 vestingDuration,
    uint256 feeTarget
  );

  event Deposit(address sender, uint256 indexed nftId);

  event Withdraw(address sender, uint256 indexed nftId);

  event Join(uint256 indexed nftId, uint256 indexed pId, uint256 indexed liq);

  event Exit(address to, uint256 indexed nftId, uint256 indexed pId, uint256 indexed liq);

  event SyncLiq(uint256 indexed nftId, uint256 indexed pId, uint256 indexed liq);

  event Harvest(address to, address reward, uint256 indexed amount);

  event EmergencyEnabled();

  event EmergencyWithdrawForOwner(address reward, uint256 indexed amount);

  event EmergencyWithdraw(address sender, uint256 indexed nftId);
}

File 20 of 25 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

File 21 of 25 : 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 22 of 25 : IAccessControl.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 23 of 25 : 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 24 of 25 : Strings.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

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

File 25 of 25 : ERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC165.sol";

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

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

Contract ABI

[{"inputs":[{"internalType":"contract IERC721","name":"_nft","type":"address"},{"internalType":"contract IKyberRewardLockerV2","name":"_rewardLocker","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pId","type":"uint256"},{"indexed":false,"internalType":"address","name":"poolAddress","type":"address"},{"indexed":false,"internalType":"uint32","name":"startTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"vestingDuration","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"feeTarget","type":"uint256"}],"name":"AddPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"reward","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdrawForOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"pId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"liq","type":"uint256"}],"name":"Exit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"reward","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"pId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"liq","type":"uint256"}],"name":"Join","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"startTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"vestingDuration","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"feeTarget","type":"uint256"}],"name":"RenewPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"pId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"liq","type":"uint256"}],"name":"SyncLiq","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"vestingDuration","type":"uint32"},{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint256[]","name":"rewardAmounts","type":"uint256[]"},{"internalType":"uint256","name":"feeTarget","type":"uint256"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pAddress","type":"address"},{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"checkPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyEnable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"rewards","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"emergencyWithdrawForOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pId","type":"uint256"},{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liqs","type":"uint256[]"}],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pAddr","type":"address"},{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getActiveTime","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getDepositedNFTs","outputs":[{"internalType":"uint256[]","name":"listNFTs","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getFeePool","outputs":[{"internalType":"uint256","name":"feeGrowthInside","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getJoinedPools","outputs":[{"internalType":"uint256[]","name":"poolIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"uint256","name":"fromIndex","type":"uint256"},{"internalType":"uint256","name":"toIndex","type":"uint256"}],"name":"getJoinedPoolsInRange","outputs":[{"internalType":"uint256[]","name":"poolIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getLiq","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pId","type":"uint256"}],"name":"getPoolInfo","outputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"vestingDuration","type":"uint32"},{"internalType":"uint256","name":"totalSecondsClaimed","type":"uint256"},{"internalType":"uint256","name":"feeTarget","type":"uint256"},{"internalType":"uint256","name":"numStakes","type":"uint256"},{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint256[]","name":"rewardUnclaimeds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"uint256","name":"pId","type":"uint256"}],"name":"getRewardCalculationData","outputs":[{"components":[{"internalType":"uint128","name":"secondsPerLiquidityNow","type":"uint128"},{"internalType":"int256","name":"feeNow","type":"int256"},{"internalType":"uint256","name":"vestingVolume","type":"uint256"},{"internalType":"uint256","name":"totalSecondsUnclaimed","type":"uint256"},{"internalType":"uint256","name":"secondsPerLiquidity","type":"uint256"},{"internalType":"uint256","name":"secondsClaim","type":"uint256"}],"internalType":"struct IKyberSwapElasticLM.RewardCalculationData","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getSignedFee","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getSignedFeePool","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"uint256","name":"pId","type":"uint256"}],"name":"getUserInfo","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256[]","name":"rewardPending","type":"uint256[]"},{"internalType":"uint256[]","name":"rewardLast","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"},{"internalType":"bytes[]","name":"datas","type":"bytes[]"}],"name":"harvestMultiplePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isEmergencyWithdrawnNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pId","type":"uint256"},{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liqs","type":"uint256[]"}],"name":"join","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nft","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numPools","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pools","outputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"vestingDuration","type":"uint32"},{"internalType":"uint256","name":"totalSecondsClaimed","type":"uint256"},{"internalType":"uint256","name":"feeTarget","type":"uint256"},{"internalType":"uint256","name":"numStakes","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"positions","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pId","type":"uint256"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"vestingDuration","type":"uint32"},{"internalType":"uint256[]","name":"rewardAmounts","type":"uint256[]"},{"internalType":"uint256","name":"feeTarget","type":"uint256"}],"name":"renewPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardLocker","outputs":[{"internalType":"contract IKyberRewardLockerV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakes","outputs":[{"internalType":"uint128","name":"secondsPerLiquidityLast","type":"uint128"},{"internalType":"int256","name":"feeFirst","type":"int256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b506040516200620238038062006202833981016040819052620000349162000155565b600180556001600160a01b03808316608052811660a052620000586000336200008c565b620000847f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c336200008c565b505062000194565b6200009882826200009c565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000098576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620000f83390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b03811681146200015257600080fd5b50565b600080604083850312156200016957600080fd5b825162000176816200013c565b602084015190925062000189816200013c565b809150509250929050565b60805160a051615fed62000215600039600081816103f301528181613394015281816134240152614ad20152600081816104b10152818161109001528181611add015281816125eb01528181612b830152818161307c015281816130bd01528181613aa201528181613b8301528181613cf50152614d9b0152615fed6000f3fe6080604052600436106102a45760003560e01c806361cbf76d1161016e578063affe7379116100cb578063d547741f1161007f578063dc168a9211610064578063dc168a921461090b578063e7762a0c1461093a578063f99ab49f146109af57600080fd5b8063d547741f146108cb578063d7aee3bd146108eb57600080fd5b8063b36b26c5116100b0578063b36b26c51461085b578063b63ff9161461087b578063d1941b06146108ab57600080fd5b8063affe7379146107d2578063b221e5fd146107e757600080fd5b8063983d95ce11610122578063a217fddf11610107578063a217fddf146106e3578063a51dc8f2146106f8578063ac4afa381461071857600080fd5b8063983d95ce1461066457806399fbab881461068457600080fd5b8063705b5bef11610153578063705b5bef146105e057806373770cd61461060057806391d148541461062057600080fd5b806361cbf76d146105a057806366b5a664146105c057600080fd5b806341e817ab1161021c57806349b35168116101d0578063598b8e71116101b5578063598b8e71146105405780635c6d96a91461056057806361657b121461058057600080fd5b806349b35168146104f35780634edeb8341461052057600080fd5b8063430ccd9b11610201578063430ccd9b1461048557806347ccca021461049f57806348d2e593146104d357600080fd5b806341e817ab1461042d578063420c52f21461044d57600080fd5b80632f2ff15d1161027357806335c62bc21161025857806335c62bc2146103ab57806336568abe146103c15780633892601c146103e157600080fd5b80632f2ff15d146103565780632f380b351461037657600080fd5b806301ffc9a7146102b0578063081e3eda146102e5578063180f803614610304578063248a9ca31461032657600080fd5b366102ab57005b600080fd5b3480156102bc57600080fd5b506102d06102cb36600461526c565b6109cf565b60405190151581526020015b60405180910390f35b3480156102f157600080fd5b506002545b6040519081526020016102dc565b34801561031057600080fd5b5061032461031f3660046152e2565b610a38565b005b34801561033257600080fd5b506102f661034136600461534e565b60009081526020819052604090206001015490565b34801561036257600080fd5b5061032461037136600461537c565b610c1a565b34801561038257600080fd5b5061039661039136600461534e565b610c45565b6040516102dc999897969594939291906153e7565b3480156103b757600080fd5b506102f660025481565b3480156103cd57600080fd5b506103246103dc36600461537c565b610e02565b3480156103ed57600080fd5b506104157f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102dc565b34801561043957600080fd5b50610324610448366004615490565b610e8e565b34801561045957600080fd5b5061046d61046836600461550a565b6111f2565b6040516001600160801b0390911681526020016102dc565b34801561049157600080fd5b506009546102d09060ff1681565b3480156104ab57600080fd5b506104157f000000000000000000000000000000000000000000000000000000000000000081565b3480156104df57600080fd5b506102f66104ee36600461550a565b6112b2565b3480156104ff57600080fd5b5061051361050e36600461554b565b611753565b6040516102dc9190615577565b34801561052c57600080fd5b506102f661053b36600461558a565b6118c2565b34801561054c57600080fd5b5061032461055b3660046155b6565b6118db565b34801561056c57600080fd5b5061046d61057b36600461558a565b611bfe565b34801561058c57600080fd5b5061032461059b3660046152e2565b611c17565b3480156105ac57600080fd5b506103246105bb366004615611565b611ec7565b3480156105cc57600080fd5b506103246105db366004615490565b6121ed565b3480156105ec57600080fd5b506105136105fb36600461534e565b61232e565b34801561060c57600080fd5b506102f661061b36600461550a565b6123e7565b34801561062c57600080fd5b506102d061063b36600461537c565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561067057600080fd5b5061032461067f3660046155b6565b6123f5565b34801561069057600080fd5b506106c461069f36600461534e565b600460205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b0390931683526020830191909152016102dc565b3480156106ef57600080fd5b506102f6600081565b34801561070457600080fd5b506102f661071336600461558a565b61270a565b34801561072457600080fd5b5061078761073336600461534e565b600360208190526000918252604090912080546001820154928201546004909201546001600160a01b0382169363ffffffff600160a01b8404811694600160c01b8504821694600160e01b90049091169287565b604080516001600160a01b03909816885263ffffffff968716602089015294861694870194909452939091166060850152608084015260a083019190915260c082015260e0016102dc565b3480156107de57600080fd5b5061032461271f565b3480156107f357600080fd5b50610836610802366004615699565b600560208181526000938452604080852090915291835291208054600482015491909201546001600160801b039092169183565b604080516001600160801b0390941684526020840192909252908201526060016102dc565b34801561086757600080fd5b506105136108763660046156bb565b6127b7565b34801561088757600080fd5b506102d061089636600461534e565b60086020526000908152604090205460ff1681565b3480156108b757600080fd5b506103246108c63660046155b6565b6127db565b3480156108d757600080fd5b506103246108e636600461537c565b612c9e565b3480156108f757600080fd5b506102d061090636600461550a565b612cc4565b34801561091757600080fd5b5061092b610926366004615699565b612d90565b6040516102dc939291906156d8565b34801561094657600080fd5b5061095a610955366004615699565b613005565b6040516102dc9190600060c0820190506001600160801b0383511682526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b3480156109bb57600080fd5b506103246109ca366004615703565b613167565b60006001600160e01b031982167f7965db0b000000000000000000000000000000000000000000000000000000001480610a3257507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b60026001541415610a905760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60026001558281808214610ad75760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b6044820152606401610a87565b60005b85811015610c0d573360046000898985818110610af957610af96157bf565b60209081029290920135835250810191909152604001600020546001600160a01b031614610b695760405162461bcd60e51b815260206004820152601260248201527f686172766573743a206e6f74206f776e657200000000000000000000000000006044820152606401610a87565b6000858583818110610b7d57610b7d6157bf565b9050602002810190610b8f91906157d5565b810190610b9c91906158b0565b905060005b815151811015610bfa57610bea898985818110610bc057610bc06157bf565b9050602002013583600001518381518110610bdd57610bdd6157bf565b60200260200101516135d6565b610bf38161599b565b9050610ba1565b505080610c069061599b565b9050610ada565b5050600180555050505050565b600082815260208190526040902060010154610c3681336138d5565b610c408383613953565b505050565b60008181526003602081905260409091208054600182015492820154600483015460028401546001600160a01b0384169563ffffffff600160a01b8604811696600160c01b8704821696600160e01b9004909116949193919260609182918067ffffffffffffffff811115610cbc57610cbc61581c565b604051908082528060200260200182016040528015610ce5578160200160208202803683370190505b5093508067ffffffffffffffff811115610d0157610d0161581c565b604051908082528060200260200182016040528015610d2a578160200160208202803683370190505b50925060005b81811015610df257826002018181548110610d4d57610d4d6157bf565b600091825260209091206002909102015485516001600160a01b0390911690869083908110610d7e57610d7e6157bf565b60200260200101906001600160a01b031690816001600160a01b031681525050826002018181548110610db357610db36157bf565b906000526020600020906002020160010154848281518110610dd757610dd76157bf565b6020908102919091010152610deb8161599b565b9050610d30565b5050509193959799909294969850565b6001600160a01b0381163314610e805760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610a87565b610e8a82826139f1565b5050565b60026001541415610ee15760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a87565b60026001558281808214610f285760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b6044820152606401610a87565b8660025411610f6b5760405162461bcd60e51b815260206004820152600f60248201526e506f6f6c206e6f742065786973747360881b6044820152606401610a87565b6000878152600360205260409020805463ffffffff428116600160a01b9092041611801590610fad57508054600160c01b900463ffffffff164263ffffffff16105b610ff95760405162461bcd60e51b815260206004820152600c60248201527f496e76616c69642074696d6500000000000000000000000000000000000000006044820152606401610a87565b60005b868110156111e35733600460008a8a8581811061101b5761101b6157bf565b60209081029290920135835250810191909152604001600020546001600160a01b03161461108b5760405162461bcd60e51b815260206004820152600960248201527f4e6f74206f776e657200000000000000000000000000000000000000000000006044820152606401610a87565b6110cd7f00000000000000000000000000000000000000000000000000000000000000008989848181106110c1576110c16157bf565b90506020020135611bfe565b6001600160801b0316600460008a8a858181106110ec576110ec6157bf565b905060200201358152602001908152602001600020600101819055506000600560008a8a85818110611120576111206157bf565b90506020020135815260200190815260200160002060008b815260200190815260200160002090508060050154600014156111965761119189898481811061116a5761116a6157bf565b905060200201358b898986818110611184576111846157bf565b9050602002013586613a70565b6111d2565b6111d28989848181106111ab576111ab6157bf565b905060200201358b8989868181106111c5576111c56157bf565b9050602002013586613dd9565b506111dc8161599b565b9050610ffc565b50506001805550505050505050565b6000806111ff848461407b565b606081015160808201516040517fb231a3b8000000000000000000000000000000000000000000000000000000008152600292830b6004820152910b60248201529091506001600160a01b0386169063b231a3b89060440160206040518083038186803b15801561126f57600080fd5b505afa158015611283573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a791906159cd565b9150505b9392505050565b6000806112bf848461407b565b606081015160405163f30dba9360e01b815260029190910b60048201529091506000906001600160a01b0387169063f30dba939060240160806040518083038186803b15801561130e57600080fd5b505afa158015611322573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134691906159e8565b50608085015160405163f30dba9360e01b815260029190910b6004820152909350600092506001600160a01b038916915063f30dba939060240160806040518083038186803b15801561139857600080fd5b505afa1580156113ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d091906159e8565b50925050506000876001600160a01b031663217ac2376040518163ffffffff1660e01b815260040160806040518083038186803b15801561141057600080fd5b505afa158015611424573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114489190615a60565b50509150506000886001600160a01b03166372cc51486040518163ffffffff1660e01b815260040160206040518083038186803b15801561148857600080fd5b505afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190615aab565b905060008060008b6001600160a01b031663ab612f2b6040518163ffffffff1660e01b815260040160606040518083038186803b15801561150057600080fd5b505afa158015611514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115389190615ac4565b92509250925060008c6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561157957600080fd5b505afa15801561158d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b19190615aab565b905060006115d3846001600160801b0316846001600160801b0316878561415a565b905080156117035760008e6001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b15801561161657600080fd5b505afa15801561162a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164e9190615b07565b6001600160a01b03166398c47e8c6040518163ffffffff1660e01b8152600401604080518083038186803b15801561168557600080fd5b505afa158015611699573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116bd9190615b41565b61ffff1691505080156116dc57620186a062ffffff8216830204909103905b6116fd826c01000000000000000000000000886001600160801b03166141a3565b87019650505b5050505050846060015160020b8260020b1215611724578284039550611747565b846080015160020b8260020b1261173f578383039550611747565b828401810395505b50505050509392505050565b6060818311156117a55760405162461bcd60e51b815260206004820152601360248201527f66726f6d496e646578203e20746f496e646578000000000000000000000000006044820152606401610a87565b60008481526006602052604090206117bc906142e7565b821061180a5760405162461bcd60e51b815260206004820152601160248201527f746f496e646578203e3d206c656e6774680000000000000000000000000000006044820152606401610a87565b6118148383615b8c565b61181f906001615ba3565b67ffffffffffffffff8111156118375761183761581c565b604051908082528060200260200182016040528015611860578160200160208202803683370190505b509050825b8281116118ba57600085815260066020526040902061188490826142f1565b8261188f8684615b8c565b8151811061189f5761189f6157bf565b60209081029190910101526118b38161599b565b9050611865565b509392505050565b6000806118cf848461407b565b60e00151949350505050565b600954339060ff1660005b83811015611bf75781158061192b57506008600086868481811061190c5761190c6157bf565b602090810292909201358352508101919091526040016000205460ff16155b6119775760405162461bcd60e51b815260206004820152601660248201527f4e6f7420616c6c6f77656420746f206465706f736974000000000000000000006044820152606401610a87565b8115806119b4575060086000868684818110611995576119956157bf565b602090810292909201358352508101919091526040016000205460ff16155b611a005760405162461bcd60e51b815260206004820152601660248201527f4e6f7420616c6c6f77656420746f206465706f736974000000000000000000006044820152606401610a87565b8260046000878785818110611a1757611a176157bf565b90506020020135815260200190815260200160002060000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611a8f858583818110611a6857611a686157bf565b6001600160a01b0387166000908152600760209081526040909120939102013590506142fd565b611adb5760405162461bcd60e51b815260206004820152601760248201527f4661696c20746f20616464206465706f7369744e4654730000000000000000006044820152606401610a87565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd8430888886818110611b1e57611b1e6157bf565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015611b7557600080fd5b505af1158015611b89573d6000803e3d6000fd5b50505050848482818110611b9f57611b9f6157bf565b6040516001600160a01b038716815260209182029390930135927fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c92500160405180910390a280611bef8161599b565b9150506118e6565b5050505050565b600080611c0b848461407b565b60a00151949350505050565b6000611c2381336138d5565b8382808214611c655760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b6044820152606401610a87565b60005b86811015611ebd576000888883818110611c8457611c846157bf565b9050602002016020810190611c9991906156bb565b6001600160a01b03161415611ddc57600033878784818110611cbd57611cbd6157bf565b9050602002013560405160006040518083038185875af1925050503d8060008114611d04576040519150601f19603f3d011682016040523d82523d6000602084013e611d09565b606091505b5050905080611d5a5760405162461bcd60e51b815260206004820152601c60248201527f7472616e736665722072657761726420746f6b656e206661696c6564000000006044820152606401610a87565b868683818110611d6c57611d6c6157bf565b905060200201357f4042b7789d1f6c4d5a798b447cfb918e82b64dd68b81d78ddc4dd1944ba5c51c8a8a85818110611da657611da66157bf565b9050602002016020810190611dbb91906156bb565b6040516001600160a01b03909116815260200160405180910390a250611ead565b611e3033878784818110611df257611df26157bf565b905060200201358a8a85818110611e0b57611e0b6157bf565b9050602002016020810190611e2091906156bb565b6001600160a01b03169190614309565b858582818110611e4257611e426157bf565b905060200201357f4042b7789d1f6c4d5a798b447cfb918e82b64dd68b81d78ddc4dd1944ba5c51c898984818110611e7c57611e7c6157bf565b9050602002016020810190611e9191906156bb565b6040516001600160a01b03909116815260200160405180910390a25b611eb68161599b565b9050611c68565b5050505050505050565b7f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c611ef281336138d5565b6000888152600360205260409020805463ffffffff428116600160a01b909204161180611f2f5750805463ffffffff428116600160c01b90920416105b611f7b5760405162461bcd60e51b815260206004820152601960248201527f72656e65773a20696e76616c696420706f6f6c207374617465000000000000006044820152606401610a87565b60028101548414611fce5760405162461bcd60e51b815260206004820152601560248201527f72656e65773a20696e76616c6964206c656e67746800000000000000000000006044820152606401610a87565b4263ffffffff168863ffffffff16118015611ff457508763ffffffff168763ffffffff16115b6120405760405162461bcd60e51b815260206004820152601460248201527f72656e65773a20696e76616c69642074696d65730000000000000000000000006044820152606401610a87565b6004810154156120925760405162461bcd60e51b815260206004820152601660248201527f72656e65773a20706f6f6c20686173207374616b6573000000000000000000006044820152606401610a87565b80547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff16600160a01b63ffffffff8a8116919091027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1691909117600160c01b89831602177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160e01b91881691909102178155600060018201819055600382018490555b8481101561218f5785858281811061214f5761214f6157bf565b9050602002013582600201828154811061216b5761216b6157bf565b60009182526020909120600160029092020101556121888161599b565b9050612135565b506040805163ffffffff8a8116825289811660208301528816818301526060810185905290518a917fb9c850b340173835986142ca0df0b53080dd84e5ba2a82cb567e3324b4c2ef03919081900360800190a2505050505050505050565b600260015414156122405760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a87565b600260015582818082146122875760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b6044820152606401610a87565b86600254116122ca5760405162461bcd60e51b815260206004820152600f60248201526e506f6f6c206e6f742065786973747360881b6044820152606401610a87565b60005b85811015612320576123108787838181106122ea576122ea6157bf565b9050602002013589878785818110612304576123046157bf565b9050602002013561439a565b6123198161599b565b90506122cd565b505060018055505050505050565b600081815260066020526040812060609190612349906142e7565b90508067ffffffffffffffff8111156123645761236461581c565b60405190808252806020026020018201604052801561238d578160200160208202803683370190505b50915060005b818110156123e05760008481526006602052604090206123b390826142f1565b8382815181106123c5576123c56157bf565b60209081029190910101526123d98161599b565b9050612393565b5050919050565b6000806112a78585856112b2565b3360005b8281101561270457600060046000868685818110612419576124196157bf565b6020908102929092013583525081019190915260400160002080549091506001600160a01b038481169116146124915760405162461bcd60e51b815260206004820152601360248201527f77697468647261773a206e6f74206f776e6572000000000000000000000000006044820152606401610a87565b6124c4600660008787868181106124aa576124aa6157bf565b9050602002013581526020019081526020016000206142e7565b156125115760405162461bcd60e51b815260206004820152601860248201527f77697468647261773a206e6f74206578697465642079657400000000000000006044820152606401610a87565b60046000868685818110612527576125276157bf565b602090810292909201358352508101919091526040016000908120805473ffffffffffffffffffffffffffffffffffffffff191681556001015561259d858584818110612576576125766157bf565b6001600160a01b038716600090815260076020908152604090912093910201359050614871565b6125e95760405162461bcd60e51b815260206004820152601a60248201527f4661696c20746f2072656d6f7665206465706f7369744e4654730000000000006044820152606401610a87565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd308588888781811061262c5761262c6157bf565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561268357600080fd5b505af1158015612697573d6000803e3d6000fd5b505050508484838181106126ad576126ad6157bf565b6040516001600160a01b038716815260209182029390930135927f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436492500160405180910390a2506126fd8161599b565b90506123f9565b50505050565b60008061271784846118c2565b949350505050565b600061272b81336138d5565b60095460ff161561277e5760405162461bcd60e51b815260206004820152600d60248201527f496e76616c69642076616c7565000000000000000000000000000000000000006044820152606401610a87565b6009805460ff191660011790556040517f1d8c7af3ae0426053ea40080543aa1cbe5bea5cdb7a55888b4cca96eea0493e490600090a150565b6001600160a01b0381166000908152600760205260409020606090610a329061487d565b600954339060ff1660005b83811015611bf757600060046000878785818110612806576128066157bf565b6020908102929092013583525081019190915260400160002080549091506001600160a01b0385811691161461287e5760405162461bcd60e51b815260206004820152601360248201527f77697468647261773a206e6f74206f776e6572000000000000000000000000006044820152606401610a87565b600160086000888886818110612896576128966157bf565b90506020020135815260200190815260200160002060006101000a81548160ff02191690831515021790555060006128f7600660008989878181106128dd576128dd6157bf565b90506020020135815260200190815260200160002061487d565b905060005b81518110156129dd576000828281518110612919576129196157bf565b6020908102919091018101516000818152600390925260408220600401805460001901905591506005908a8a88818110612955576129556157bf565b602090810292909201358352508181019290925260409081016000908120848252909252812080546fffffffffffffffffffffffffffffffff19168155906129a060018301826151eb565b6129ae6002830160006151eb565b6129bc6003830160006151eb565b50600060048201819055600590910155506129d68161599b565b90506128fc565b50600460008888868181106129f4576129f46157bf565b602090810292909201358352508101919091526040016000908120805473ffffffffffffffffffffffffffffffffffffffff191681556001015583612b8157612a6f878785818110612a4857612a486157bf565b6001600160a01b038916600090815260076020908152604090912093910201359050614871565b612abb5760405162461bcd60e51b815260206004820152601a60248201527f4661696c20746f2072656d6f7665206465706f7369744e4654730000000000006044820152606401610a87565b60005b8151811015612b7f576000828281518110612adb57612adb6157bf565b60200260200101519050612b2281600660008c8c8a818110612aff57612aff6157bf565b90506020020135815260200190815260200160002061487190919063ffffffff16565b612b6e5760405162461bcd60e51b815260206004820152601a60248201527f4661696c20746f2072656d6f7665206a6f696e6564506f6f6c730000000000006044820152606401610a87565b50612b788161599b565b9050612abe565b505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd30878a8a88818110612bc457612bc46157bf565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015612c1b57600080fd5b505af1158015612c2f573d6000803e3d6000fd5b50505050868684818110612c4557612c456157bf565b6040516001600160a01b038916815260209182029390930135927f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd969592500160405180910390a2505080612c979061599b565b90506127e6565b600082815260208190526040902060010154612cba81336138d5565b610c4083836139f1565b600080612cd1848461407b565b60408082015190517f4bfe33980000000000000000000000000000000000000000000000000000000081526001600160a01b03888116600483015292935069ffffffffffffffffffff90911691861690634bfe33989060240160206040518083038186803b158015612d4257600080fd5b505afa158015612d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d7a9190615bd5565b69ffffffffffffffffffff161495945050505050565b6000818152600360209081526040808320858452600580845282852086865290935290832091820154606092839291612e0b5760405162461bcd60e51b815260206004820152601b60248201527f67657455736572496e666f3a206e6f74206a6f696e65642079657400000000006044820152606401610a87565b600282015467ffffffffffffffff811115612e2857612e2861581c565b604051908082528060200260200182016040528015612e51578160200160208202803683370190505b50600283015490945067ffffffffffffffff811115612e7257612e7261581c565b604051908082528060200260200182016040528015612e9b578160200160208202803683370190505b5092506000612eaa8888613005565b905060005b6002840154811015612ff3576000612efb8460050154866002018481548110612eda57612eda6157bf565b9060005260206000209060020201600101548560600151866080015161488a565b90506000612f5782866003018581548110612f1857612f186157bf565b9060005260206000200154612f2d9190615ba3565b8560400151876001018681548110612f4757612f476157bf565b90600052602060002001546148b5565b905080856002018481548110612f6f57612f6f6157bf565b9060005260206000200154612f849190615ba3565b888481518110612f9657612f966157bf565b602002602001018181525050846001018381548110612fb757612fb76157bf565b9060005260206000200154878481518110612fd457612fd46157bf565b602002602001018181525050505080612fec9061599b565b9050612eaf565b50816005015495505050509250925092565b6130476040518060c0016040528060006001600160801b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008281526003602090815260408083208684526005835281842086855290925290912081546130a1906001600160a01b03167f0000000000000000000000000000000000000000000000000000000000000000876111f2565b6001600160801b0316835281546130e2906001600160a01b03167f0000000000000000000000000000000000000000000000000000000000000000876123e7565b60208401819052600482015460038401546130fe9291906148ec565b60408401528154600183015461312c9163ffffffff600160a01b8204811692600160c01b9092041690614935565b6060840152805483516001600160801b039182169003166080840181905260058201546131599190615bf0565b60a084015250909392505050565b7f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c61319281336138d5565b84838082146131d45760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b6044820152606401610a87565b4263ffffffff168b63ffffffff16101580156131fb57508a63ffffffff168a63ffffffff16115b6132475760405162461bcd60e51b815260206004820152601660248201527f616464506f6f6c3a20696e76616c69642074696d6573000000000000000000006044820152606401610a87565b6000600254905060006003600083815260200190815260200160002090508d8160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508c8160000160146101000a81548163ffffffff021916908363ffffffff1602179055508b8160000160186101000a81548163ffffffff021916908363ffffffff1602179055508a81600001601c6101000a81548163ffffffff021916908363ffffffff1602179055506000816001018190555085816003018190555060005b8981101561353f5760008b8b83818110613329576133296157bf565b905060200201602081019061333e91906156bb565b6001600160a01b03161415801561341a57508a8a82818110613362576133626157bf565b905060200201602081019061337791906156bb565b604051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152919091169063dd62ed3e9060440160206040518083038186803b1580156133e057600080fd5b505afa1580156133f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134189190615aab565b155b1561347d5761347d7f00000000000000000000000000000000000000000000000000000000000000006000198d8d85818110613458576134586157bf565b905060200201602081019061346d91906156bb565b6001600160a01b03169190614988565b8160020160405180604001604052808d8d8581811061349e5761349e6157bf565b90506020020160208101906134b391906156bb565b6001600160a01b031681526020018b8b858181106134d3576134d36157bf565b602090810292909201359092528354600180820186556000958652948290208451600290920201805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909216919091178155920151919092015550806135378161599b565b91505061330d565b50600280549060006135508361599b565b9190505550817f54113f5df645f88beae3d09a9f1db87099fec8d97302b6f8b43f8d5abed2e2e38f8f8f8f8b6040516135be9594939291906001600160a01b0395909516855263ffffffff938416602086015291831660408501529091166060830152608082015260a00190565b60405180910390a25050505050505050505050505050565b80600254116136195760405162461bcd60e51b815260206004820152600f60248201526e506f6f6c206e6f742065786973747360881b6044820152606401610a87565b600081815260036020908152604080832085845260048352818420600580855283862087875290945291909320918201549091906136995760405162461bcd60e51b815260206004820152601760248201527f686172766573743a206e6f74206a6f696e6564207965740000000000000000006044820152606401610a87565b60006136a58686613005565b90508060a001518460010160008282546136bf9190615ba3565b9091555050805182546fffffffffffffffffffffffffffffffff19166001600160801b0390911617825560005b60028501548110156138cc5760006137178460050154876002018481548110612eda57612eda6157bf565b905080156137915780846003018381548110613735576137356157bf565b90600052602060002001600082825461374e9190615ba3565b925050819055508086600201838154811061376b5761376b6157bf565b9060005260206000209060020201600101600082825461378b9190615b8c565b90915550505b60006137d08560030184815481106137ab576137ab6157bf565b90600052602060002001548560400151876001018681548110612f4757612f476157bf565b90506000818660020185815481106137ea576137ea6157bf565b90600052602060002001546137ff9190615ba3565b905080156138b85781156138425781866001018581548110613823576138236157bf565b90600052602060002001600082825461383c9190615ba3565b90915550505b6000866002018581548110613859576138596157bf565b90600052602060002001819055506138b888600201858154811061387f5761387f6157bf565b600091825260209091206002909102015488548a546001600160a01b0392831692909116908490600160e01b900463ffffffff16614a62565b505050806138c59061599b565b90506136ec565b50505050505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610e8a57613911816001600160a01b03166014614b7f565b61391c836020614b7f565b60405160200161392d929190615c3b565b60408051601f198184030181529082905262461bcd60e51b8252610a8791600401615cbc565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610e8a576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556139ad3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610e8a576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000848152600460209081526040808320600583528184208785529092529091208254613ac7906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000088612cc4565b613b135760405162461bcd60e51b815260206004820152601260248201527f6a6f696e3a20696e76616c696420706f6f6c00000000000000000000000000006044820152606401610a87565b8315801590613b26575081600101548411155b613b725760405162461bcd60e51b815260206004820152601160248201527f6a6f696e3a20696e76616c6964206c69710000000000000000000000000000006044820152606401610a87565b8254613ba8906001600160a01b03167f0000000000000000000000000000000000000000000000000000000000000000886111f2565b81546fffffffffffffffffffffffffffffffff19166001600160801b0391909116178155600283015467ffffffffffffffff811115613be957613be961581c565b604051908082528060200260200182016040528015613c12578160200160208202803683370190505b508051613c2991600184019160209091019061520c565b50600283015467ffffffffffffffff811115613c4757613c4761581c565b604051908082528060200260200182016040528015613c70578160200160208202803683370190505b508051613c8791600284019160209091019061520c565b50600283015467ffffffffffffffff811115613ca557613ca561581c565b604051908082528060200260200182016040528015613cce578160200160208202803683370190505b508051613ce591600384019160209091019061520c565b50600383015415613d2057613d1a7f00000000000000000000000000000000000000000000000000000000000000008761270a565b60048201555b60058101849055600483018054906000613d398361599b565b90915550506000868152600660205260409020613d5690866142fd565b613da25760405162461bcd60e51b815260206004820152601760248201527f4661696c20746f20616464206a6f696e6564506f6f6c730000000000000000006044820152606401610a87565b8385877f5d48292d83151281e6ea967de9fd35716c713dc76c11beb42d78ed5110270f7360405160405180910390a4505050505050565b6000848152600460209081526040808320600583528184208785529092529091208315801590613e1b575060018201546005820154613e189086615ba3565b11155b613e675760405162461bcd60e51b815260206004820152601160248201527f73796e633a20696e76616c6964206c69710000000000000000000000000000006044820152606401610a87565b6000613e738787613005565b905060005b6002850154811015613fbd576000613ea38460050154876002018481548110612eda57612eda6157bf565b90508015613f1d5780846003018381548110613ec157613ec16157bf565b906000526020600020016000828254613eda9190615ba3565b9250508190555080866002018381548110613ef757613ef76157bf565b90600052602060002090600202016001016000828254613f179190615b8c565b90915550505b6000613f378560030184815481106137ab576137ab6157bf565b90508015613faa5780856001018481548110613f5557613f556157bf565b906000526020600020016000828254613f6e9190615ba3565b9250508190555080856002018481548110613f8b57613f8b6157bf565b906000526020600020016000828254613fa49190615ba3565b90915550505b505080613fb69061599b565b9050613e78565b508060a00151846001016000828254613fd69190615ba3565b9091555050805182546fffffffffffffffffffffffffffffffff19166001600160801b03909116178255600482015460208201516003860154600585015461402293929190898c614d60565b82600401819055508482600501600082825461403e9190615ba3565b90915550506040518590879089907ff31cd5db84a4ab16cd339c510d5a60c63ef5818c538aa67046f5bc0dca794cd390600090a450505050505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101919091526040517f99fbab88000000000000000000000000000000000000000000000000000000008152600481018390526000906001600160a01b038516906399fbab88906024016101606040518083038186803b15801561411957600080fd5b505afa15801561412d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141519190615d65565b50949350505050565b60008061418c6001600160801b0385166141748789615b8c565b614187896001600160801b038916615ba3565b6141a3565b90506141998382876141a3565b9695505050505050565b60008080600019858709858702925082811083820303915050806000141561422057600084116142155760405162461bcd60e51b815260206004820152600760248201527f302064656e6f6d000000000000000000000000000000000000000000000000006044820152606401610a87565b5082900490506112ab565b80841161426f5760405162461bcd60e51b815260206004820152600e60248201527f64656e6f6d203c3d2070726f64310000000000000000000000000000000000006044820152606401610a87565b600084868809808403938111909203919050600061428f86196001615ba3565b8616958690049560026003880281188089028203028089028203028089028203028089028203028089028203028089029091030260008290038290046001019490940294049390931791909102925050509392505050565b6000610a32825490565b60006112ab8383614e06565b60006112ab8383614e30565b6040516001600160a01b038316602482015260448101829052610c409084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152614e7f565b60008281526003602090815260408083208684526004835281842060058452828520878652909352922081546001600160a01b031633148061442857508254600160c01b900463ffffffff164263ffffffff1611801561442857503360009081527f84779ab8c2db004a3e75bfe114d2b98838cc68288e8e29039ab1b1e132f853bc602052604090205460ff165b61449a5760405162461bcd60e51b815260206004820152602160248201527f657869743a206e6f74206f776e6572206f7220706f6f6c206e6f7420656e646560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a87565b83158015906144ad575080600501548411155b6144f95760405162461bcd60e51b815260206004820152601160248201527f657869743a20696e76616c6964206c69710000000000000000000000000000006044820152606401610a87565b6005810154600061450a8683615b8c565b905060006145188989613005565b90508060a001518660010160008282546145329190615ba3565b9091555050805184546fffffffffffffffffffffffffffffffff19166001600160801b039091161784556005840182905560005b600287015481101561474257600061458d85896002018481548110612eda57612eda6157bf565b9050801561460757808660030183815481106145ab576145ab6157bf565b9060005260206000200160008282546145c49190615ba3565b92505081905550808860020183815481106145e1576145e16157bf565b906000526020600020906002020160010160008282546146019190615b8c565b90915550505b6000614646876003018481548110614621576146216157bf565b90600052602060002001548560400151896001018681548110612f4757612f476157bf565b9050600081886002018581548110614660576146606157bf565b90600052602060002001546146759190615ba3565b9050801561472e5781156146b85781886001018581548110614699576146996157bf565b9060005260206000200160008282546146b29190615ba3565b90915550505b60008860020185815481106146cf576146cf6157bf565b906000526020600020018190555061472e8a60020185815481106146f5576146f56157bf565b60009182526020909120600290910201548a548c546001600160a01b0392831692909116908490600160e01b900463ffffffff16614a62565b5050508061473b9061599b565b9050614566565b508161482d5760008981526005602090815260408083208b8452909152812080546fffffffffffffffffffffffffffffffff191681559061478660018301826151eb565b6147946002830160006151eb565b6147a26003830160006151eb565b506000600482810182905560059092018190559087018054916147c483615e35565b909155505060008981526006602052604090206147e19089614871565b61482d5760405162461bcd60e51b815260206004820152601a60248201527f4661696c20746f2072656d6f7665206a6f696e6564506f6f6c730000000000006044820152606401610a87565b604051338152879089908b907f275029c7b988945c03ac5499c0d532fce79ce36efab42e1b3f180a62001cad2c9060200160405180910390a4505050505050505050565b60006112ab8383614f64565b606060006112ab83615057565b600082826148988688615bf0565b6148a29190615bf0565b6148ac9190615e4c565b95945050505050565b60008064e8d4a510006148c88587615bf0565b6148d29190615e4c565b90508281116148e25760006112a7565b6112a78382615b8c565b6000816148ff575064e8d4a510006112ab565b600061490b8486615e60565b90506112a78361492064e8d4a5100084615bf0565b61492a9190615e4c565b64e8d4a510006150b3565b600080846149494263ffffffff16866150c9565b6149539190615b8c565b9050600061496e826c01000000000000000000000000615bf0565b905083811161497e576000614199565b6141998482615b8c565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b1580156149d457600080fd5b505afa1580156149e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a0c9190615aab565b614a169190615ba3565b6040516001600160a01b0385166024820152604481018290529091506127049085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161434e565b60006001600160a01b03851615614a7a576000614a7c565b825b6040517f1e2fabb60000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015286811660248301526044820186905263ffffffff851660648301529192507f000000000000000000000000000000000000000000000000000000000000000090911690631e2fabb69083906084016000604051808303818588803b158015614b1957600080fd5b505af1158015614b2d573d6000803e3d6000fd5b5050604080516001600160a01b03808a1682528a1660208201528794507fa0306f61d3fafe13787b78e276cb6b644382854a66cb46daae14227d3ec26797935001905060405180910390a25050505050565b60606000614b8e836002615bf0565b614b99906002615ba3565b67ffffffffffffffff811115614bb157614bb161581c565b6040519080825280601f01601f191660200182016040528015614bdb576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110614c1257614c126157bf565b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110614c5d57614c5d6157bf565b60200101906001600160f81b031916908160001a9053506000614c81846002615bf0565b614c8c906001615ba3565b90505b6001811115614d11577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110614ccd57614ccd6157bf565b1a60f81b828281518110614ce357614ce36157bf565b60200101906001600160f81b031916908160001a90535060049490941c93614d0a81615e35565b9050614c8f565b5083156112ab5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a87565b600084614d6f57506000614199565b600087614d7c8789615e60565b12614d9057614d8b8688615e60565b614d92565b875b90506000614dc07f00000000000000000000000000000000000000000000000000000000000000008561270a565b614dca9086615e9f565b614dd48388615e9f565b614dde9190615f26565b90506000614dec8688615ba3565b9050614df88183615f65565b9a9950505050505050505050565b6000826000018281548110614e1d57614e1d6157bf565b9060005260206000200154905092915050565b6000818152600183016020526040812054614e7757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610a32565b506000610a32565b6000614ed4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166150e09092919063ffffffff16565b805190915015610c405780806020019051810190614ef29190615f93565b610c405760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a87565b6000818152600183016020526040812054801561504d576000614f88600183615b8c565b8554909150600090614f9c90600190615b8c565b9050818114615001576000866000018281548110614fbc57614fbc6157bf565b9060005260206000200154905080876000018481548110614fdf57614fdf6157bf565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061501257615012615fae565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610a32565b6000915050610a32565b6060816000018054806020026020016040519081016040528092919081815260200182805480156150a757602002820191906000526020600020905b815481526020019060010190808311615093575b50505050509050919050565b6000818310156150c357826112ab565b50919050565b6000818310156150d957816112ab565b5090919050565b6060612717848460008585843b6151395760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a87565b600080866001600160a01b031685876040516151559190615fc4565b60006040518083038185875af1925050503d8060008114615192576040519150601f19603f3d011682016040523d82523d6000602084013e615197565b606091505b50915091506151a78282866151b2565b979650505050505050565b606083156151c15750816112ab565b8251156151d15782518084602001fd5b8160405162461bcd60e51b8152600401610a879190615cbc565b50805460008255906000526020600020908101906152099190615257565b50565b828054828255906000526020600020908101928215615247579160200282015b8281111561524757825182559160200191906001019061522c565b50615253929150615257565b5090565b5b808211156152535760008155600101615258565b60006020828403121561527e57600080fd5b81356001600160e01b0319811681146112ab57600080fd5b60008083601f8401126152a857600080fd5b50813567ffffffffffffffff8111156152c057600080fd5b6020830191508360208260051b85010111156152db57600080fd5b9250929050565b600080600080604085870312156152f857600080fd5b843567ffffffffffffffff8082111561531057600080fd5b61531c88838901615296565b9096509450602087013591508082111561533557600080fd5b5061534287828801615296565b95989497509550505050565b60006020828403121561536057600080fd5b5035919050565b6001600160a01b038116811461520957600080fd5b6000806040838503121561538f57600080fd5b8235915060208301356153a181615367565b809150509250929050565b600081518084526020808501945080840160005b838110156153dc578151875295820195908201906001016153c0565b509495945050505050565b60006101208083016001600160a01b03808e168552602063ffffffff808f1682880152808e166040880152808d166060880152508a60808701528960a08701528860c08701528360e0870152829350875180845261014087019450818901935060005b8181101561546857845184168652948201949382019360010161544a565b505050505082810361010084015261548081856153ac565b9c9b505050505050505050505050565b6000806000806000606086880312156154a857600080fd5b85359450602086013567ffffffffffffffff808211156154c757600080fd5b6154d389838a01615296565b909650945060408801359150808211156154ec57600080fd5b506154f988828901615296565b969995985093965092949392505050565b60008060006060848603121561551f57600080fd5b833561552a81615367565b9250602084013561553a81615367565b929592945050506040919091013590565b60008060006060848603121561556057600080fd5b505081359360208301359350604090920135919050565b6020815260006112ab60208301846153ac565b6000806040838503121561559d57600080fd5b82356155a881615367565b946020939093013593505050565b600080602083850312156155c957600080fd5b823567ffffffffffffffff8111156155e057600080fd5b6155ec85828601615296565b90969095509350505050565b803563ffffffff8116811461560c57600080fd5b919050565b600080600080600080600060c0888a03121561562c57600080fd5b8735965061563c602089016155f8565b955061564a604089016155f8565b9450615658606089016155f8565b9350608088013567ffffffffffffffff81111561567457600080fd5b6156808a828b01615296565b989b979a5095989497959660a090950135949350505050565b600080604083850312156156ac57600080fd5b50508035926020909101359150565b6000602082840312156156cd57600080fd5b81356112ab81615367565b8381526060602082015260006156f160608301856153ac565b828103604084015261419981856153ac565b600080600080600080600080600060e08a8c03121561572157600080fd5b893561572c81615367565b985061573a60208b016155f8565b975061574860408b016155f8565b965061575660608b016155f8565b955060808a013567ffffffffffffffff8082111561577357600080fd5b61577f8d838e01615296565b909750955060a08c013591508082111561579857600080fd5b506157a58c828d01615296565b9a9d999c50979a9699959894979660c00135949350505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126157ec57600080fd5b83018035915067ffffffffffffffff82111561580757600080fd5b6020019150368190038213156152db57600080fd5b634e487b7160e01b600052604160045260246000fd5b6040516020810167ffffffffffffffff811182821017156158555761585561581c565b60405290565b604051610100810167ffffffffffffffff811182821017156158555761585561581c565b604051601f8201601f1916810167ffffffffffffffff811182821017156158a8576158a861581c565b604052919050565b600060208083850312156158c357600080fd5b823567ffffffffffffffff808211156158db57600080fd5b81850191508282870312156158ef57600080fd5b6158f7615832565b82358281111561590657600080fd5b80840193505086601f84011261591b57600080fd5b82358281111561592d5761592d61581c565b8060051b925061593e85840161587f565b818152928401850192858101908985111561595857600080fd5b948601945b848610156159765785358252948601949086019061595d565b83525090979650505050505050565b634e487b7160e01b600052601160045260246000fd5b60006000198214156159af576159af615985565b5060010190565b80516001600160801b038116811461560c57600080fd5b6000602082840312156159df57600080fd5b6112ab826159b6565b600080600080608085870312156159fe57600080fd5b615a07856159b6565b9350602085015180600f0b8114615a1d57600080fd5b60408601519093509150615a33606086016159b6565b905092959194509250565b8051600281900b811461560c57600080fd5b8051801515811461560c57600080fd5b60008060008060808587031215615a7657600080fd5b8451615a8181615367565b9350615a8f60208601615a3e565b9250615a9d60408601615a3e565b9150615a3360608601615a50565b600060208284031215615abd57600080fd5b5051919050565b600080600060608486031215615ad957600080fd5b615ae2846159b6565b9250615af0602085016159b6565b9150615afe604085016159b6565b90509250925092565b600060208284031215615b1957600080fd5b81516112ab81615367565b805161560c81615367565b805161ffff8116811461560c57600080fd5b60008060408385031215615b5457600080fd5b8251615b5f81615367565b9150615b6d60208401615b2f565b90509250929050565b634e487b7160e01b600052601260045260246000fd5b600082821015615b9e57615b9e615985565b500390565b60008219821115615bb657615bb6615985565b500190565b805169ffffffffffffffffffff8116811461560c57600080fd5b600060208284031215615be757600080fd5b6112ab82615bbb565b6000816000190483118215151615615c0a57615c0a615985565b500290565b60005b83811015615c2a578181015183820152602001615c12565b838111156127045750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615c73816017850160208801615c0f565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351615cb0816028840160208801615c0f565b01602801949350505050565b6020815260008251806020840152615cdb816040850160208701615c0f565b601f01601f19169190910160400192915050565b600060608284031215615d0157600080fd5b6040516060810181811067ffffffffffffffff82111715615d2457615d2461581c565b80604052508091508251615d3781615367565b8152615d4560208401615b2f565b60208201526040830151615d5881615367565b6040919091015292915050565b600080828403610160811215615d7a57600080fd5b61010080821215615d8a57600080fd5b615d9261585b565b915084516bffffffffffffffffffffffff81168114615db057600080fd5b8252615dbe60208601615b24565b6020830152615dcf60408601615bbb565b6040830152615de060608601615a3e565b6060830152615df160808601615a3e565b6080830152615e0260a086016159b6565b60a083015260c085015160c083015260e085015160e0830152819350615e2a86828701615cef565b925050509250929050565b600081615e4457615e44615985565b506000190190565b600082615e5b57615e5b615b76565b500490565b600080831283600160ff1b01831281151615615e7e57615e7e615985565b836001600160ff1b03018313811615615e9957615e99615985565b50500390565b60006001600160ff1b03600084136000841385830485118282161615615ec757615ec7615985565b600160ff1b6000871286820588128184161615615ee657615ee6615985565b60008712925087820587128484161615615f0257615f02615985565b87850587128184161615615f1857615f18615985565b505050929093029392505050565b6000808212826001600160ff1b0303841381151615615f4757615f47615985565b82600160ff1b038412811615615f5f57615f5f615985565b50500190565b600082615f7457615f74615b76565b600160ff1b821460001984141615615f8e57615f8e615985565b500590565b600060208284031215615fa557600080fd5b6112ab82615a50565b634e487b7160e01b600052603160045260246000fd5b60008251615fd6818460208701615c0f565b919091019291505056fea164736f6c6343000809000a0000000000000000000000002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000226314996cdfa694a196ef5e3d9a26b35bb40eca

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

0000000000000000000000002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8000000000000000000000000226314996cdfa694a196ef5e3d9a26b35bb40eca

-----Decoded View---------------
Arg [0] : _nft (address): 0x2b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8
Arg [1] : _rewardLocker (address): 0x226314996cdfa694a196ef5e3d9a26b35bb40eca

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000002b1c7b41f6a8f2b2bc45c3233a5d5fb3cd6dc9a8
Arg [1] : 000000000000000000000000226314996cdfa694a196ef5e3d9a26b35bb40eca


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.