ETH Price: $3,353.41 (-0.40%)
Gas: 4 Gwei

Contract

0xeb02addCfD8B773A5FFA6B9d1FE99c566f8c44CC
 
Transaction Hash
Method
Block
From
To
0x1201291d53a29570fc7406771134ee273eaec6ab1906e90dcbdcd6448c854219 Bond(pending)2024-07-28 5:07:042 days ago1722143224IN
0xeb02addC...66f8c44CC
0 ETH(Pending)(Pending)
Bond204114042024-07-29 9:44:5922 hrs ago1722246299IN
0xeb02addC...66f8c44CC
0 ETH0.000362283.68244058
Unbond204112172024-07-29 9:07:2323 hrs ago1722244043IN
0xeb02addC...66f8c44CC
0 ETH0.000229733.02030083
Withdraw204112132024-07-29 9:06:3523 hrs ago1722243995IN
0xeb02addC...66f8c44CC
0 ETH0.000308233.09380285
Unbond203962562024-07-27 7:01:353 days ago1722063695IN
0xeb02addC...66f8c44CC
0 ETH0.000127781.68052557
Withdraw203962542024-07-27 7:01:113 days ago1722063671IN
0xeb02addC...66f8c44CC
0 ETH0.000147131.71183838
Withdraw203544622024-07-21 10:57:598 days ago1721559479IN
0xeb02addC...66f8c44CC
0 ETH0.000182742.12622517
Unbond202978402024-07-13 13:19:3516 days ago1720876775IN
0xeb02addC...66f8c44CC
0 ETH0.000172842.27232822
Withdraw202978352024-07-13 13:18:3516 days ago1720876715IN
0xeb02addC...66f8c44CC
0 ETH0.000220582.21404309
Unbond202890202024-07-12 7:46:4718 days ago1720770407IN
0xeb02addC...66f8c44CC
0 ETH0.000376374.94966122
Withdraw202890182024-07-12 7:46:2318 days ago1720770383IN
0xeb02addC...66f8c44CC
0 ETH0.000390894.54794892
Unbond202522342024-07-07 4:25:3523 days ago1720326335IN
0xeb02addC...66f8c44CC
0 ETH0.000118161.65898272
Activate202522262024-07-07 4:23:5923 days ago1720326239IN
0xeb02addC...66f8c44CC
0 ETH0.00021631.54959923
Add Job202386562024-07-05 6:56:4725 days ago1720162607IN
0xeb02addC...66f8c44CC
0 ETH0.0017913518.34016563
Migrate Job202384652024-07-05 6:18:2325 days ago1720160303IN
0xeb02addC...66f8c44CC
0 ETH0.0009546813.54621403
Add Job202384542024-07-05 6:16:1125 days ago1720160171IN
0xeb02addC...66f8c44CC
0 ETH0.0012553112.85209628
Activate202383522024-07-05 5:55:3525 days ago1720158935IN
0xeb02addC...66f8c44CC
0 ETH0.0018122615.61113497
Bond202350752024-07-04 18:56:1125 days ago1720119371IN
0xeb02addC...66f8c44CC
0 ETH0.000572657.29655478
Activate202347472024-07-04 17:49:5925 days ago1720115399IN
0xeb02addC...66f8c44CC
0 ETH0.0014378712.38606443
Bond202306462024-07-04 4:04:5926 days ago1720065899IN
0xeb02addC...66f8c44CC
0 ETH0.000331472.61507384
Bond202130132024-07-01 16:58:3528 days ago1719853115IN
0xeb02addC...66f8c44CC
0 ETH0.000817278.3070882
Bond202125832024-07-01 15:32:2328 days ago1719847943IN
0xeb02addC...66f8c44CC
0 ETH0.0018609518.91543561
Unbond201885782024-06-28 7:05:3532 days ago1719558335IN
0xeb02addC...66f8c44CC
0 ETH0.000248593.2692724
Withdraw201885742024-06-28 7:04:4732 days ago1719558287IN
0xeb02addC...66f8c44CC
0 ETH0.000267633.11389404
Unbond201836302024-06-27 14:29:4732 days ago1719498587IN
0xeb02addC...66f8c44CC
0 ETH0.0010270613.50262872
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Keep3r

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 33 runs

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

/*

Coded for The Keep3r Network with ♥ by

██████╗░███████╗███████╗██╗  ░██╗░░░░░░░██╗░█████╗░███╗░░██╗██████╗░███████╗██████╗░██╗░░░░░░█████╗░███╗░░██╗██████╗░
██╔══██╗██╔════╝██╔════╝██║  ░██║░░██╗░░██║██╔══██╗████╗░██║██╔══██╗██╔════╝██╔══██╗██║░░░░░██╔══██╗████╗░██║██╔══██╗
██║░░██║█████╗░░█████╗░░██║  ░╚██╗████╗██╔╝██║░░██║██╔██╗██║██║░░██║█████╗░░██████╔╝██║░░░░░███████║██╔██╗██║██║░░██║
██║░░██║██╔══╝░░██╔══╝░░██║  ░░████╔═████║░██║░░██║██║╚████║██║░░██║██╔══╝░░██╔══██╗██║░░░░░██╔══██║██║╚████║██║░░██║
██████╔╝███████╗██║░░░░░██║  ░░╚██╔╝░╚██╔╝░╚█████╔╝██║░╚███║██████╔╝███████╗██║░░██║███████╗██║░░██║██║░╚███║██████╔╝
╚═════╝░╚══════╝╚═╝░░░░░╚═╝  ░░░╚═╝░░░╚═╝░░░╚════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝╚═╝░░╚══╝╚═════╝░

https://defi.sucks

*/

pragma solidity >=0.8.4 <0.9.0;

import './peripherals/jobs/Keep3rJobs.sol';
import './peripherals/keepers/Keep3rKeepers.sol';
import './peripherals/Keep3rAccountance.sol';
import './peripherals/Keep3rRoles.sol';
import './peripherals/Keep3rParameters.sol';
import './peripherals/DustCollector.sol';

contract Keep3r is DustCollector, Keep3rJobs, Keep3rKeepers {
  constructor(
    address _governance,
    address _keep3rHelper,
    address _keep3rV1,
    address _keep3rV1Proxy,
    address _kp3rWethPool
  ) Keep3rParameters(_keep3rHelper, _keep3rV1, _keep3rV1Proxy, _kp3rWethPool) Keep3rRoles(_governance) DustCollector() {}
}

File 2 of 39 : Keep3rJobs.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './Keep3rJobDisputable.sol';
import './Keep3rJobWorkable.sol';
import './Keep3rJobManager.sol';

abstract contract Keep3rJobs is Keep3rJobDisputable, Keep3rJobManager, Keep3rJobWorkable {}

File 3 of 39 : Keep3rKeepers.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './Keep3rKeeperDisputable.sol';

abstract contract Keep3rKeepers is Keep3rKeeperDisputable {}

File 4 of 39 : Keep3rAccountance.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import '../../interfaces/peripherals/IKeep3rAccountance.sol';

abstract contract Keep3rAccountance is IKeep3rAccountance {
  using EnumerableSet for EnumerableSet.AddressSet;

  /// @notice List of all enabled keepers
  EnumerableSet.AddressSet internal _keepers;

  /// @inheritdoc IKeep3rAccountance
  mapping(address => uint256) public override workCompleted;

  /// @inheritdoc IKeep3rAccountance
  mapping(address => uint256) public override firstSeen;

  /// @inheritdoc IKeep3rAccountance
  mapping(address => bool) public override disputes;

  /// @inheritdoc IKeep3rAccountance
  /// @notice Mapping (job => bonding => amount)
  mapping(address => mapping(address => uint256)) public override bonds;

  /// @inheritdoc IKeep3rAccountance
  mapping(address => mapping(address => uint256)) public override jobTokenCredits;

  /// @notice The current liquidity credits available for a job
  mapping(address => uint256) internal _jobLiquidityCredits;

  /// @notice Map the address of a job to its correspondent periodCredits
  mapping(address => uint256) internal _jobPeriodCredits;

  /// @notice Enumerable array of Job Tokens for Credits
  mapping(address => EnumerableSet.AddressSet) internal _jobTokens;

  /// @notice List of liquidities that a job has (job => liquidities)
  mapping(address => EnumerableSet.AddressSet) internal _jobLiquidities;

  /// @notice Liquidity pool to observe
  mapping(address => address) internal _liquidityPool;

  /// @notice Tracks if a pool has KP3R as token0
  mapping(address => bool) internal _isKP3RToken0;

  /// @inheritdoc IKeep3rAccountance
  mapping(address => mapping(address => uint256)) public override pendingBonds;

  /// @inheritdoc IKeep3rAccountance
  mapping(address => mapping(address => uint256)) public override canActivateAfter;

  /// @inheritdoc IKeep3rAccountance
  mapping(address => mapping(address => uint256)) public override canWithdrawAfter;

  /// @inheritdoc IKeep3rAccountance
  mapping(address => mapping(address => uint256)) public override pendingUnbonds;

  /// @inheritdoc IKeep3rAccountance
  mapping(address => bool) public override hasBonded;

  /// @notice List of all enabled jobs
  EnumerableSet.AddressSet internal _jobs;

  /// @inheritdoc IKeep3rAccountance
  function jobs() external view override returns (address[] memory _list) {
    _list = _jobs.values();
  }

  /// @inheritdoc IKeep3rAccountance
  function keepers() external view override returns (address[] memory _list) {
    _list = _keepers.values();
  }
}

File 5 of 39 : Keep3rRoles.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '../../interfaces/peripherals/IKeep3rRoles.sol';
import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import './Governable.sol';

contract Keep3rRoles is IKeep3rRoles, Governable {
  /// @inheritdoc IKeep3rRoles
  mapping(address => bool) public override slashers;

  /// @inheritdoc IKeep3rRoles
  mapping(address => bool) public override disputers;

  constructor(address _governance) Governable(_governance) {}

  /// @inheritdoc IKeep3rRoles
  function addSlasher(address _slasher) external override onlyGovernance {
    if (slashers[_slasher]) revert SlasherExistent();
    slashers[_slasher] = true;
    emit SlasherAdded(_slasher);
  }

  /// @inheritdoc IKeep3rRoles
  function removeSlasher(address _slasher) external override onlyGovernance {
    if (!slashers[_slasher]) revert SlasherUnexistent();
    delete slashers[_slasher];
    emit SlasherRemoved(_slasher);
  }

  /// @inheritdoc IKeep3rRoles
  function addDisputer(address _disputer) external override onlyGovernance {
    if (disputers[_disputer]) revert DisputerExistent();
    disputers[_disputer] = true;
    emit DisputerAdded(_disputer);
  }

  /// @inheritdoc IKeep3rRoles
  function removeDisputer(address _disputer) external override onlyGovernance {
    if (!disputers[_disputer]) revert DisputerUnexistent();
    delete disputers[_disputer];
    emit DisputerRemoved(_disputer);
  }

  /// @notice Functions with this modifier can only be called by either a slasher or governance
  modifier onlySlasher {
    if (!slashers[msg.sender]) revert OnlySlasher();
    _;
  }

  /// @notice Functions with this modifier can only be called by either a disputer or governance
  modifier onlyDisputer {
    if (!disputers[msg.sender]) revert OnlyDisputer();
    _;
  }
}

File 6 of 39 : Keep3rParameters.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '../../interfaces/IKeep3rHelper.sol';
import '../../interfaces/peripherals/IKeep3rParameters.sol';
import './Keep3rAccountance.sol';
import './Keep3rRoles.sol';

abstract contract Keep3rParameters is IKeep3rParameters, Keep3rAccountance, Keep3rRoles {
  /// @inheritdoc IKeep3rParameters
  address public override keep3rV1;

  /// @inheritdoc IKeep3rParameters
  address public override keep3rV1Proxy;

  /// @inheritdoc IKeep3rParameters
  address public override keep3rHelper;

  /// @inheritdoc IKeep3rParameters
  address public override kp3rWethPool;

  /// @inheritdoc IKeep3rParameters
  uint256 public override bondTime = 3 days;

  /// @inheritdoc IKeep3rParameters
  uint256 public override unbondTime = 14 days;

  /// @inheritdoc IKeep3rParameters
  uint256 public override liquidityMinimum = 3 ether;

  /// @inheritdoc IKeep3rParameters
  uint256 public override rewardPeriodTime = 5 days;

  /// @inheritdoc IKeep3rParameters
  uint256 public override inflationPeriod = 34 days;

  /// @inheritdoc IKeep3rParameters
  uint256 public override fee = 30;

  /// @notice The base that will be used to calculate the fee
  uint256 internal constant _BASE = 10_000;

  /// @notice The minimum reward period
  uint256 internal constant _MIN_REWARD_PERIOD_TIME = 1 days;

  constructor(
    address _keep3rHelper,
    address _keep3rV1,
    address _keep3rV1Proxy,
    address _kp3rWethPool
  ) {
    keep3rHelper = _keep3rHelper;
    keep3rV1 = _keep3rV1;
    keep3rV1Proxy = _keep3rV1Proxy;
    kp3rWethPool = _kp3rWethPool;
    _liquidityPool[kp3rWethPool] = kp3rWethPool;
    _isKP3RToken0[_kp3rWethPool] = IKeep3rHelper(keep3rHelper).isKP3RToken0(kp3rWethPool);
  }

  /// @inheritdoc IKeep3rParameters
  function setKeep3rHelper(address _keep3rHelper) external override onlyGovernance {
    if (_keep3rHelper == address(0)) revert ZeroAddress();
    keep3rHelper = _keep3rHelper;
    emit Keep3rHelperChange(_keep3rHelper);
  }

  /// @inheritdoc IKeep3rParameters
  function setKeep3rV1(address _keep3rV1) external override onlyGovernance {
    if (_keep3rV1 == address(0)) revert ZeroAddress();
    keep3rV1 = _keep3rV1;
    emit Keep3rV1Change(_keep3rV1);
  }

  /// @inheritdoc IKeep3rParameters
  function setKeep3rV1Proxy(address _keep3rV1Proxy) external override onlyGovernance {
    if (_keep3rV1Proxy == address(0)) revert ZeroAddress();
    keep3rV1Proxy = _keep3rV1Proxy;
    emit Keep3rV1ProxyChange(_keep3rV1Proxy);
  }

  /// @inheritdoc IKeep3rParameters
  function setKp3rWethPool(address _kp3rWethPool) external override onlyGovernance {
    if (_kp3rWethPool == address(0)) revert ZeroAddress();
    kp3rWethPool = _kp3rWethPool;
    _liquidityPool[kp3rWethPool] = kp3rWethPool;
    _isKP3RToken0[_kp3rWethPool] = IKeep3rHelper(keep3rHelper).isKP3RToken0(_kp3rWethPool);
    emit Kp3rWethPoolChange(_kp3rWethPool);
  }

  /// @inheritdoc IKeep3rParameters
  function setBondTime(uint256 _bondTime) external override onlyGovernance {
    bondTime = _bondTime;
    emit BondTimeChange(_bondTime);
  }

  /// @inheritdoc IKeep3rParameters
  function setUnbondTime(uint256 _unbondTime) external override onlyGovernance {
    unbondTime = _unbondTime;
    emit UnbondTimeChange(_unbondTime);
  }

  /// @inheritdoc IKeep3rParameters
  function setLiquidityMinimum(uint256 _liquidityMinimum) external override onlyGovernance {
    liquidityMinimum = _liquidityMinimum;
    emit LiquidityMinimumChange(_liquidityMinimum);
  }

  /// @inheritdoc IKeep3rParameters
  // TODO: check what happens to credit minting when changing this. Shouldn't we update the cached ticks?
  function setRewardPeriodTime(uint256 _rewardPeriodTime) external override onlyGovernance {
    if (_rewardPeriodTime < _MIN_REWARD_PERIOD_TIME) revert MinRewardPeriod();
    rewardPeriodTime = _rewardPeriodTime;
    emit RewardPeriodTimeChange(_rewardPeriodTime);
  }

  /// @inheritdoc IKeep3rParameters
  function setInflationPeriod(uint256 _inflationPeriod) external override onlyGovernance {
    inflationPeriod = _inflationPeriod;
    emit InflationPeriodChange(_inflationPeriod);
  }

  /// @inheritdoc IKeep3rParameters
  function setFee(uint256 _fee) external override onlyGovernance {
    fee = _fee;
    emit FeeChange(_fee);
  }
}

File 7 of 39 : DustCollector.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.4 <0.9.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '../../contracts/peripherals/Governable.sol';
import '../../interfaces/peripherals/IDustCollector.sol';

abstract contract DustCollector is IDustCollector, Governable {
  using SafeERC20 for IERC20;

  address internal constant _ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

  function sendDust(
    address _token,
    uint256 _amount,
    address _to
  ) external override onlyGovernance {
    if (_to == address(0)) revert ZeroAddress();
    if (_token == _ETH_ADDRESS) {
      payable(_to).transfer(_amount);
    } else {
      IERC20(_token).safeTransfer(_to, _amount);
    }
    emit DustSent(_token, _amount, _to);
  }
}

File 8 of 39 : Keep3rJobDisputable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './Keep3rJobFundableCredits.sol';
import './Keep3rJobFundableLiquidity.sol';
import '../Keep3rDisputable.sol';

abstract contract Keep3rJobDisputable is IKeep3rJobDisputable, Keep3rDisputable, Keep3rJobFundableCredits, Keep3rJobFundableLiquidity {
  using EnumerableSet for EnumerableSet.AddressSet;
  using SafeERC20 for IERC20;

  /// @inheritdoc IKeep3rJobDisputable
  function slashTokenFromJob(
    address _job,
    address _token,
    uint256 _amount
  ) external override onlySlasher {
    if (!disputes[_job]) revert NotDisputed();
    if (!_jobTokens[_job].contains(_token)) revert JobTokenUnexistent();
    if (jobTokenCredits[_job][_token] < _amount) revert JobTokenInsufficient();

    try IERC20(_token).transfer(governance, _amount) {} catch {}
    jobTokenCredits[_job][_token] -= _amount;
    if (jobTokenCredits[_job][_token] == 0) {
      _jobTokens[_job].remove(_token);
    }

    emit JobSlashToken(_job, _token, msg.sender, _amount);
  }

  /// @inheritdoc IKeep3rJobDisputable
  function slashLiquidityFromJob(
    address _job,
    address _liquidity,
    uint256 _amount
  ) external override onlySlasher {
    if (!disputes[_job]) revert NotDisputed();

    _unbondLiquidityFromJob(_job, _liquidity, _amount);
    try IERC20(_liquidity).transfer(governance, _amount) {} catch {}
    emit JobSlashLiquidity(_job, _liquidity, msg.sender, _amount);
  }
}

File 9 of 39 : Keep3rJobWorkable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './Keep3rJobMigration.sol';
import '../../../interfaces/IKeep3rHelper.sol';
import '../../../interfaces/peripherals/IKeep3rJobs.sol';

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';

abstract contract Keep3rJobWorkable is IKeep3rJobWorkable, Keep3rJobMigration {
  using EnumerableSet for EnumerableSet.AddressSet;
  using SafeERC20 for IERC20;

  uint256 internal _initialGas;

  /// @inheritdoc IKeep3rJobWorkable
  function isKeeper(address _keeper) external override returns (bool _isKeeper) {
    _initialGas = _getGasLeft();
    if (_keepers.contains(_keeper)) {
      emit KeeperValidation(_initialGas);
      return true;
    }
  }

  /// @inheritdoc IKeep3rJobWorkable
  function isBondedKeeper(
    address _keeper,
    address _bond,
    uint256 _minBond,
    uint256 _earned,
    uint256 _age
  ) public override returns (bool _isBondedKeeper) {
    _initialGas = _getGasLeft();
    if (
      _keepers.contains(_keeper) &&
      bonds[_keeper][_bond] >= _minBond &&
      workCompleted[_keeper] >= _earned &&
      block.timestamp - firstSeen[_keeper] >= _age
    ) {
      emit KeeperValidation(_initialGas);
      return true;
    }
  }

  /// @inheritdoc IKeep3rJobWorkable
  function worked(address _keeper) external override {
    address _job = msg.sender;
    if (disputes[_job]) revert JobDisputed();
    if (!_jobs.contains(_job)) revert JobUnapproved();

    if (_updateJobCreditsIfNeeded(_job)) {
      emit LiquidityCreditsReward(_job, rewardedAt[_job], _jobLiquidityCredits[_job], _jobPeriodCredits[_job]);
    }

    (uint256 _boost, uint256 _oneEthQuote, uint256 _extraGas) = IKeep3rHelper(keep3rHelper).getPaymentParams(bonds[_keeper][keep3rV1]);

    uint256 _gasLeft = _getGasLeft();
    uint256 _payment = _calculatePayment(_gasLeft, _extraGas, _oneEthQuote, _boost);

    if (_payment > _jobLiquidityCredits[_job]) {
      _rewardJobCredits(_job);
      emit LiquidityCreditsReward(_job, rewardedAt[_job], _jobLiquidityCredits[_job], _jobPeriodCredits[_job]);

      _gasLeft = _getGasLeft();
      _payment = _calculatePayment(_gasLeft, _extraGas, _oneEthQuote, _boost);
    }

    _bondedPayment(_job, _keeper, _payment);
    emit KeeperWork(keep3rV1, _job, _keeper, _payment, _gasLeft);
  }

  /// @inheritdoc IKeep3rJobWorkable
  function bondedPayment(address _keeper, uint256 _payment) public override {
    address _job = msg.sender;

    if (disputes[_job]) revert JobDisputed();
    if (!_jobs.contains(_job)) revert JobUnapproved();

    if (_updateJobCreditsIfNeeded(_job)) {
      emit LiquidityCreditsReward(_job, rewardedAt[_job], _jobLiquidityCredits[_job], _jobPeriodCredits[_job]);
    }

    if (_payment > _jobLiquidityCredits[_job]) {
      _rewardJobCredits(_job);
      emit LiquidityCreditsReward(_job, rewardedAt[_job], _jobLiquidityCredits[_job], _jobPeriodCredits[_job]);
    }

    _bondedPayment(_job, _keeper, _payment);
    emit KeeperWork(keep3rV1, _job, _keeper, _payment, _getGasLeft());
  }

  /// @inheritdoc IKeep3rJobWorkable
  function directTokenPayment(
    address _token,
    address _keeper,
    uint256 _amount
  ) external override {
    address _job = msg.sender;

    if (disputes[_job]) revert JobDisputed();
    if (disputes[_keeper]) revert Disputed();
    if (!_jobs.contains(_job)) revert JobUnapproved();
    if (jobTokenCredits[_job][_token] < _amount) revert InsufficientFunds();
    jobTokenCredits[_job][_token] -= _amount;
    IERC20(_token).safeTransfer(_keeper, _amount);
    emit KeeperWork(_token, _job, _keeper, _amount, _getGasLeft());
  }

  function _bondedPayment(
    address _job,
    address _keeper,
    uint256 _payment
  ) internal {
    if (_payment > _jobLiquidityCredits[_job]) revert InsufficientFunds();

    workedAt[_job] = block.timestamp;
    _jobLiquidityCredits[_job] -= _payment;
    bonds[_keeper][keep3rV1] += _payment;
    workCompleted[_keeper] += _payment;
  }

  /// @notice Calculate amount to be payed in KP3R, taking into account multiple parameters
  /// @param _gasLeft Amount of gas left after working the job
  /// @param _extraGas Amount of expected unaccounted gas
  /// @param _oneEthQuote Amount of KP3R equivalent to 1 ETH
  /// @param _boost Reward given to the keeper for having bonded KP3R tokens
  /// @return _payment Amount to be payed in KP3R tokens
  function _calculatePayment(
    uint256 _gasLeft,
    uint256 _extraGas,
    uint256 _oneEthQuote,
    uint256 _boost
  ) internal view returns (uint256 _payment) {
    uint256 _accountedGas = _initialGas - _gasLeft + _extraGas;
    _payment = (((_accountedGas * _boost) / _BASE) * _oneEthQuote) / 1 ether;
  }

  /// @notice Return the gas left and add 1/64 in order to match real gas left at first level of depth (EIP-150)
  /// @return _gasLeft Amount of gas left recording taking into account EIP-150
  function _getGasLeft() internal view returns (uint256 _gasLeft) {
    _gasLeft = (gasleft() * 64) / 63;
  }
}

File 10 of 39 : Keep3rJobManager.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './Keep3rJobOwnership.sol';
import '../Keep3rRoles.sol';
import '../Keep3rParameters.sol';
import '../../../interfaces/peripherals/IKeep3rJobs.sol';

abstract contract Keep3rJobManager is IKeep3rJobManager, Keep3rJobOwnership, Keep3rRoles, Keep3rParameters {
  using EnumerableSet for EnumerableSet.AddressSet;

  /// @inheritdoc IKeep3rJobManager
  function addJob(address _job) external override {
    if (_jobs.contains(_job)) revert JobAlreadyAdded();
    if (hasBonded[_job]) revert AlreadyAKeeper();
    _jobs.add(_job);
    jobOwner[_job] = msg.sender;
    emit JobAddition(msg.sender, _job);
  }
}

File 11 of 39 : Keep3rJobFundableCredits.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './Keep3rJobOwnership.sol';
import '../Keep3rAccountance.sol';
import '../Keep3rParameters.sol';
import '../../../interfaces/peripherals/IKeep3rJobs.sol';

import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/utils/math/Math.sol';

abstract contract Keep3rJobFundableCredits is IKeep3rJobFundableCredits, ReentrancyGuard, Keep3rJobOwnership, Keep3rParameters {
  using EnumerableSet for EnumerableSet.AddressSet;
  using SafeERC20 for IERC20;

  /// @notice Cooldown between withdrawals
  uint256 internal constant _WITHDRAW_TOKENS_COOLDOWN = 1 minutes;

  /// @inheritdoc IKeep3rJobFundableCredits
  mapping(address => mapping(address => uint256)) public override jobTokenCreditsAddedAt;

  /// @inheritdoc IKeep3rJobFundableCredits
  function addTokenCreditsToJob(
    address _job,
    address _token,
    uint256 _amount
  ) external override nonReentrant {
    if (!_jobs.contains(_job)) revert JobUnavailable();
    // KP3R shouldn't be used for direct token payments
    if (_token == keep3rV1) revert TokenUnallowed();
    uint256 _before = IERC20(_token).balanceOf(address(this));
    IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
    uint256 _received = IERC20(_token).balanceOf(address(this)) - _before;
    uint256 _tokenFee = (_received * fee) / _BASE;
    jobTokenCredits[_job][_token] += _received - _tokenFee;
    jobTokenCreditsAddedAt[_job][_token] = block.timestamp;
    IERC20(_token).safeTransfer(governance, _tokenFee);
    _jobTokens[_job].add(_token);

    emit TokenCreditAddition(_job, _token, msg.sender, _received);
  }

  /// @inheritdoc IKeep3rJobFundableCredits
  function withdrawTokenCreditsFromJob(
    address _job,
    address _token,
    uint256 _amount,
    address _receiver
  ) external override nonReentrant onlyJobOwner(_job) {
    if (block.timestamp <= jobTokenCreditsAddedAt[_job][_token] + _WITHDRAW_TOKENS_COOLDOWN) revert JobTokenCreditsLocked();
    if (jobTokenCredits[_job][_token] < _amount) revert InsufficientJobTokenCredits();
    if (disputes[_job]) revert JobDisputed();

    jobTokenCredits[_job][_token] -= _amount;
    IERC20(_token).safeTransfer(_receiver, _amount);

    if (jobTokenCredits[_job][_token] == 0) {
      _jobTokens[_job].remove(_token);
    }

    emit TokenCreditWithdrawal(_job, _token, _receiver, _amount);
  }
}

File 12 of 39 : Keep3rJobFundableLiquidity.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './Keep3rJobOwnership.sol';
import '../Keep3rAccountance.sol';
import '../Keep3rParameters.sol';
import '../../../interfaces/IPairManager.sol';
import '../../../interfaces/peripherals/IKeep3rJobs.sol';

import '../../libraries/FullMath.sol';

import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/utils/math/Math.sol';

abstract contract Keep3rJobFundableLiquidity is IKeep3rJobFundableLiquidity, ReentrancyGuard, Keep3rJobOwnership, Keep3rParameters {
  using EnumerableSet for EnumerableSet.AddressSet;
  using SafeERC20 for IERC20;

  /// @notice List of liquidities that are accepted in the system
  EnumerableSet.AddressSet internal _approvedLiquidities;

  /// @inheritdoc IKeep3rJobFundableLiquidity
  mapping(address => mapping(address => uint256)) public override liquidityAmount;

  /// @inheritdoc IKeep3rJobFundableLiquidity
  mapping(address => uint256) public override rewardedAt;

  /// @inheritdoc IKeep3rJobFundableLiquidity
  mapping(address => uint256) public override workedAt;

  /// @notice Tracks an address and returns its TickCache
  mapping(address => TickCache) internal _tick;

  // Views

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function approvedLiquidities() external view override returns (address[] memory _list) {
    _list = _approvedLiquidities.values();
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function jobPeriodCredits(address _job) public view override returns (uint256 _periodCredits) {
    for (uint256 i; i < _jobLiquidities[_job].length(); i++) {
      address _liquidity = _jobLiquidities[_job].at(i);
      if (_approvedLiquidities.contains(_liquidity)) {
        TickCache memory _tickCache = observeLiquidity(_liquidity);
        if (_tickCache.period != 0) {
          int56 _tickDifference = _isKP3RToken0[_liquidity] ? _tickCache.difference : -_tickCache.difference;
          _periodCredits += _getReward(
            IKeep3rHelper(keep3rHelper).getKP3RsAtTick(liquidityAmount[_job][_liquidity], _tickDifference, rewardPeriodTime)
          );
        }
      }
    }
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function jobLiquidityCredits(address _job) public view override returns (uint256 _liquidityCredits) {
    uint256 _periodCredits = jobPeriodCredits(_job);

    // If the job was rewarded in the past 1 period time
    if ((block.timestamp - rewardedAt[_job]) < rewardPeriodTime) {
      // If the job has period credits, update minted job credits to new twap
      _liquidityCredits = _periodCredits > 0
        ? (_jobLiquidityCredits[_job] * _periodCredits) / _jobPeriodCredits[_job] // If the job has period credits, return remaining job credits updated to new twap
        : _jobLiquidityCredits[_job]; // If not, return remaining credits, forced credits should not be updated
    } else {
      // Else return a full period worth of credits if current credits have expired
      _liquidityCredits = _periodCredits;
    }
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function totalJobCredits(address _job) external view override returns (uint256 _credits) {
    uint256 _periodCredits = jobPeriodCredits(_job);
    uint256 _cooldown = block.timestamp;

    if ((rewardedAt[_job] > _period(block.timestamp - rewardPeriodTime))) {
      // Will calculate cooldown if it outdated
      if ((block.timestamp - rewardedAt[_job]) >= rewardPeriodTime) {
        // Will calculate cooldown from last reward reference in this period
        _cooldown -= (rewardedAt[_job] + rewardPeriodTime);
      } else {
        // Will calculate cooldown from last reward timestamp
        _cooldown -= rewardedAt[_job];
      }
    } else {
      // Will calculate cooldown from period start if expired
      _cooldown -= _period(block.timestamp);
    }
    _credits = jobLiquidityCredits(_job) + _phase(_cooldown, _periodCredits);
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function quoteLiquidity(address _liquidity, uint256 _amount) external view override returns (uint256 _periodCredits) {
    if (_approvedLiquidities.contains(_liquidity)) {
      TickCache memory _tickCache = observeLiquidity(_liquidity);
      if (_tickCache.period != 0) {
        int56 _tickDifference = _isKP3RToken0[_liquidity] ? _tickCache.difference : -_tickCache.difference;
        return _getReward(IKeep3rHelper(keep3rHelper).getKP3RsAtTick(_amount, _tickDifference, rewardPeriodTime));
      }
    }
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function observeLiquidity(address _liquidity) public view override returns (TickCache memory _tickCache) {
    if (_tick[_liquidity].period == _period(block.timestamp)) {
      // Will return cached twaps if liquidity is updated
      _tickCache = _tick[_liquidity];
    } else {
      bool success;
      uint256 lastPeriod = _period(block.timestamp - rewardPeriodTime);

      if (_tick[_liquidity].period == lastPeriod) {
        // Will only ask for current period accumulator if liquidity is outdated
        uint32[] memory _secondsAgo = new uint32[](1);
        int56 previousTick = _tick[_liquidity].current;

        _secondsAgo[0] = uint32(block.timestamp - _period(block.timestamp));

        (_tickCache.current, , success) = IKeep3rHelper(keep3rHelper).observe(_liquidityPool[_liquidity], _secondsAgo);

        _tickCache.difference = _tickCache.current - previousTick;
      } else if (_tick[_liquidity].period < lastPeriod) {
        // Will ask for 2 accumulators if liquidity is expired
        uint32[] memory _secondsAgo = new uint32[](2);

        _secondsAgo[0] = uint32(block.timestamp - _period(block.timestamp));
        _secondsAgo[1] = uint32(block.timestamp - _period(block.timestamp) + rewardPeriodTime);

        int56 _tickCumulative2;
        (_tickCache.current, _tickCumulative2, success) = IKeep3rHelper(keep3rHelper).observe(_liquidityPool[_liquidity], _secondsAgo);

        _tickCache.difference = _tickCache.current - _tickCumulative2;
      }
      if (success) {
        _tickCache.period = _period(block.timestamp);
      } else {
        delete _tickCache.period;
      }
    }
  }

  // Methods

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function forceLiquidityCreditsToJob(address _job, uint256 _amount) external override onlyGovernance {
    if (!_jobs.contains(_job)) revert JobUnavailable();
    _settleJobAccountance(_job);
    _jobLiquidityCredits[_job] += _amount;
    emit LiquidityCreditsForced(_job, rewardedAt[_job], _jobLiquidityCredits[_job]);
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function approveLiquidity(address _liquidity) external override onlyGovernance {
    if (!_approvedLiquidities.add(_liquidity)) revert LiquidityPairApproved();
    _liquidityPool[_liquidity] = IPairManager(_liquidity).pool();
    _isKP3RToken0[_liquidity] = IKeep3rHelper(keep3rHelper).isKP3RToken0(_liquidityPool[_liquidity]);
    _tick[_liquidity] = observeLiquidity(_liquidity);
    emit LiquidityApproval(_liquidity);
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function revokeLiquidity(address _liquidity) external override onlyGovernance {
    if (!_approvedLiquidities.remove(_liquidity)) revert LiquidityPairUnexistent();
    emit LiquidityRevocation(_liquidity);
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function addLiquidityToJob(
    address _job,
    address _liquidity,
    uint256 _amount
  ) external override nonReentrant {
    if (!_approvedLiquidities.contains(_liquidity)) revert LiquidityPairUnapproved();
    if (!_jobs.contains(_job)) revert JobUnavailable();

    _jobLiquidities[_job].add(_liquidity);

    _settleJobAccountance(_job);

    if (_quoteLiquidity(liquidityAmount[_job][_liquidity] + _amount, _liquidity) < liquidityMinimum) revert JobLiquidityLessThanMin();

    emit LiquidityCreditsReward(_job, rewardedAt[_job], _jobLiquidityCredits[_job], _jobPeriodCredits[_job]);

    IERC20(_liquidity).safeTransferFrom(msg.sender, address(this), _amount);
    liquidityAmount[_job][_liquidity] += _amount;
    _jobPeriodCredits[_job] += _getReward(_quoteLiquidity(_amount, _liquidity));
    emit LiquidityAddition(_job, _liquidity, msg.sender, _amount);
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function unbondLiquidityFromJob(
    address _job,
    address _liquidity,
    uint256 _amount
  ) external override onlyJobOwner(_job) {
    canWithdrawAfter[_job][_liquidity] = block.timestamp + unbondTime;
    pendingUnbonds[_job][_liquidity] += _amount;
    _unbondLiquidityFromJob(_job, _liquidity, _amount);

    uint256 _remainingLiquidity = liquidityAmount[_job][_liquidity];
    if (_remainingLiquidity > 0 && _quoteLiquidity(_remainingLiquidity, _liquidity) < liquidityMinimum) revert JobLiquidityLessThanMin();

    emit Unbonding(_job, _liquidity, _amount);
  }

  /// @inheritdoc IKeep3rJobFundableLiquidity
  function withdrawLiquidityFromJob(
    address _job,
    address _liquidity,
    address _receiver
  ) external override onlyJobOwner(_job) {
    if (_receiver == address(0)) revert ZeroAddress();
    if (pendingUnbonds[_job][_liquidity] == 0) revert UnbondsUnexistent();
    if (canWithdrawAfter[_job][_liquidity] >= block.timestamp) revert UnbondsLocked();
    if (disputes[_job]) revert Disputed();

    uint256 _amount = pendingUnbonds[_job][_liquidity];

    delete pendingUnbonds[_job][_liquidity];
    delete canWithdrawAfter[_job][_liquidity];

    IERC20(_liquidity).safeTransfer(_receiver, _amount);
    emit LiquidityWithdrawal(_job, _liquidity, _receiver, _amount);
  }

  // Internal functions

  /// @notice Updates or rewards job liquidity credits depending on time since last job reward
  function _updateJobCreditsIfNeeded(address _job) internal returns (bool _rewarded) {
    if (rewardedAt[_job] < _period(block.timestamp)) {
      // Will exit function if job has been rewarded in current period
      if (rewardedAt[_job] <= _period(block.timestamp - rewardPeriodTime)) {
        // Will reset job to period syncronicity if a full period passed without rewards
        _updateJobPeriod(_job);
        _jobLiquidityCredits[_job] = _jobPeriodCredits[_job];
        rewardedAt[_job] = _period(block.timestamp);
        _rewarded = true;
      } else if ((block.timestamp - rewardedAt[_job]) >= rewardPeriodTime) {
        // Will reset job's syncronicity if last reward was more than epoch ago
        _updateJobPeriod(_job);
        _jobLiquidityCredits[_job] = _jobPeriodCredits[_job];
        rewardedAt[_job] += rewardPeriodTime;
        _rewarded = true;
      } else if (workedAt[_job] < _period(block.timestamp)) {
        // First keeper on period has to update job accountance to current twaps
        uint256 previousPeriodCredits = _jobPeriodCredits[_job];
        _updateJobPeriod(_job);
        _jobLiquidityCredits[_job] = (_jobLiquidityCredits[_job] * _jobPeriodCredits[_job]) / previousPeriodCredits;
        // Updating job accountance does not reward job
      }
    }
  }

  /// @notice Only called if _jobLiquidityCredits < payment
  function _rewardJobCredits(address _job) internal {
    /// @notice Only way to += jobLiquidityCredits is when keeper rewarding (cannot pay work)
    /* WARNING: this allows to top up _jobLiquidityCredits to a max of 1.99 but have to spend at least 1 */
    _jobLiquidityCredits[_job] += _phase(block.timestamp - rewardedAt[_job], _jobPeriodCredits[_job]);
    rewardedAt[_job] = block.timestamp;
  }

  /// @notice Updates accountance for _jobPeriodCredits
  function _updateJobPeriod(address _job) internal {
    _jobPeriodCredits[_job] = _calculateJobPeriodCredits(_job);
  }

  /// @notice Quotes the outdated job liquidities and calculates _periodCredits
  /// @dev This function is also responsible for keeping the KP3R/WETH quote updated
  function _calculateJobPeriodCredits(address _job) internal returns (uint256 _periodCredits) {
    if (_tick[kp3rWethPool].period != _period(block.timestamp)) {
      // Updates KP3R/WETH quote if needed
      _tick[kp3rWethPool] = observeLiquidity(kp3rWethPool);
    }

    for (uint256 i; i < _jobLiquidities[_job].length(); i++) {
      address _liquidity = _jobLiquidities[_job].at(i);
      if (_approvedLiquidities.contains(_liquidity)) {
        if (_tick[_liquidity].period != _period(block.timestamp)) {
          // Updates liquidity cache only if needed
          _tick[_liquidity] = observeLiquidity(_liquidity);
        }
        _periodCredits += _getReward(_quoteLiquidity(liquidityAmount[_job][_liquidity], _liquidity));
      }
    }
  }

  /// @notice Updates job accountance calculating the impact of the unbonded liquidity amount
  function _unbondLiquidityFromJob(
    address _job,
    address _liquidity,
    uint256 _amount
  ) internal nonReentrant {
    if (!_jobLiquidities[_job].contains(_liquidity)) revert JobLiquidityUnexistent();
    if (liquidityAmount[_job][_liquidity] < _amount) revert JobLiquidityInsufficient();

    // Ensures current twaps in job liquidities
    _updateJobPeriod(_job);
    uint256 _periodCreditsToRemove = _getReward(_quoteLiquidity(_amount, _liquidity));

    // A liquidity can be revoked causing a job to have 0 periodCredits
    if (_jobPeriodCredits[_job] > 0) {
      // Removes a % correspondant to a full rewardPeriodTime for the liquidity withdrawn vs all of the liquidities
      _jobLiquidityCredits[_job] -= (_jobLiquidityCredits[_job] * _periodCreditsToRemove) / _jobPeriodCredits[_job];
      _jobPeriodCredits[_job] -= _periodCreditsToRemove;
    }

    liquidityAmount[_job][_liquidity] -= _amount;
    if (liquidityAmount[_job][_liquidity] == 0) {
      _jobLiquidities[_job].remove(_liquidity);
    }
  }

  /// @notice Returns a fraction of the multiplier or the whole multiplier if equal or more than a rewardPeriodTime has passed
  function _phase(uint256 _timePassed, uint256 _multiplier) internal view returns (uint256 _result) {
    if (_timePassed < rewardPeriodTime) {
      _result = (_timePassed * _multiplier) / rewardPeriodTime;
    } else _result = _multiplier;
  }

  /// @notice Returns the start of the period of the provided timestamp
  function _period(uint256 _timestamp) internal view returns (uint256 _periodTimestamp) {
    return _timestamp - (_timestamp % rewardPeriodTime);
  }

  /// @notice Calculates relation between rewardPeriod and inflationPeriod
  function _getReward(uint256 _baseAmount) internal view returns (uint256 _credits) {
    return FullMath.mulDiv(_baseAmount, rewardPeriodTime, inflationPeriod);
  }

  /// @notice Returns underlying KP3R amount for a given liquidity amount
  function _quoteLiquidity(uint256 _amount, address _liquidity) internal view returns (uint256 _quote) {
    if (_tick[_liquidity].period != 0) {
      int56 _tickDifference = _isKP3RToken0[_liquidity] ? _tick[_liquidity].difference : -_tick[_liquidity].difference;
      _quote = IKeep3rHelper(keep3rHelper).getKP3RsAtTick(_amount, _tickDifference, rewardPeriodTime);
    }
  }

  /// @notice Updates job credits to current quotes and rewards job's pending minted credits
  /// @dev Ensures a maximum of 1 period of credits
  function _settleJobAccountance(address _job) internal virtual {
    _updateJobCreditsIfNeeded(_job);
    _rewardJobCredits(_job);
    _jobLiquidityCredits[_job] = Math.min(_jobLiquidityCredits[_job], _jobPeriodCredits[_job]);
  }
}

File 13 of 39 : Keep3rDisputable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './Keep3rParameters.sol';
import './Keep3rRoles.sol';
import '../../interfaces/peripherals/IKeep3rDisputable.sol';

abstract contract Keep3rDisputable is IKeep3rDisputable, Keep3rAccountance, Keep3rRoles {
  /// @inheritdoc IKeep3rDisputable
  function dispute(address _jobOrKeeper) external override onlyDisputer {
    if (disputes[_jobOrKeeper]) revert AlreadyDisputed();
    disputes[_jobOrKeeper] = true;
    emit Dispute(_jobOrKeeper, msg.sender);
  }

  /// @inheritdoc IKeep3rDisputable
  function resolve(address _jobOrKeeper) external override onlyDisputer {
    if (!disputes[_jobOrKeeper]) revert NotDisputed();
    disputes[_jobOrKeeper] = false;
    emit Resolve(_jobOrKeeper, msg.sender);
  }
}

File 14 of 39 : Keep3rJobOwnership.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '../../../interfaces/peripherals/IKeep3rJobs.sol';

abstract contract Keep3rJobOwnership is IKeep3rJobOwnership {
  /// @inheritdoc IKeep3rJobOwnership
  mapping(address => address) public override jobOwner;

  /// @inheritdoc IKeep3rJobOwnership
  mapping(address => address) public override jobPendingOwner;

  /// @inheritdoc IKeep3rJobOwnership
  function changeJobOwnership(address _job, address _newOwner) external override onlyJobOwner(_job) {
    jobPendingOwner[_job] = _newOwner;
    emit JobOwnershipChange(_job, jobOwner[_job], _newOwner);
  }

  /// @inheritdoc IKeep3rJobOwnership
  function acceptJobOwnership(address _job) external override onlyPendingJobOwner(_job) {
    address _previousOwner = jobOwner[_job];

    jobOwner[_job] = jobPendingOwner[_job];
    delete jobPendingOwner[_job];

    emit JobOwnershipAssent(msg.sender, _job, _previousOwner);
  }

  modifier onlyJobOwner(address _job) {
    if (msg.sender != jobOwner[_job]) revert OnlyJobOwner();
    _;
  }

  modifier onlyPendingJobOwner(address _job) {
    if (msg.sender != jobPendingOwner[_job]) revert OnlyPendingJobOwner();
    _;
  }
}

File 15 of 39 : IKeep3rJobs.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

/// @title Keep3rJobFundableCredits contract
/// @notice Handles the addition and withdrawal of credits from a job
interface IKeep3rJobFundableCredits {
  // Events

  /// @notice Emitted when Keep3rJobFundableCredits#addTokenCreditsToJob is called
  /// @param _job The address of the job being credited
  /// @param _token The address of the token being provided
  /// @param _provider The user that calls the function
  /// @param _amount The amount of credit being added to the job
  event TokenCreditAddition(address indexed _job, address indexed _token, address indexed _provider, uint256 _amount);

  /// @notice Emitted when Keep3rJobFundableCredits#withdrawTokenCreditsFromJob is called
  /// @param _job The address of the job from which the credits are withdrawn
  /// @param _token The credit being withdrawn from the job
  /// @param _receiver The user that receives the tokens
  /// @param _amount The amount of credit withdrawn
  event TokenCreditWithdrawal(address indexed _job, address indexed _token, address indexed _receiver, uint256 _amount);

  // Errors

  /// @notice Throws when the token is KP3R, as it should not be used for direct token payments
  error TokenUnallowed();

  /// @notice Throws when the token withdraw cooldown has not yet passed
  error JobTokenCreditsLocked();

  /// @notice Throws when the user tries to withdraw more tokens than it has
  error InsufficientJobTokenCredits();

  // Variables

  /// @notice Last block where tokens were added to the job
  /// @param _job The address of the job credited
  /// @param _token The address of the token credited
  /// @return _timestamp The last block where tokens were added to the job
  function jobTokenCreditsAddedAt(address _job, address _token) external view returns (uint256 _timestamp);

  // Methods

  /// @notice Add credit to a job to be paid out for work
  /// @param _job The address of the job being credited
  /// @param _token The address of the token being credited
  /// @param _amount The amount of credit being added
  function addTokenCreditsToJob(
    address _job,
    address _token,
    uint256 _amount
  ) external;

  /// @notice Withdraw credit from a job
  /// @param _job The address of the job from which the credits are withdrawn
  /// @param _token The address of the token being withdrawn
  /// @param _amount The amount of token to be withdrawn
  /// @param _receiver The user that will receive tokens
  function withdrawTokenCreditsFromJob(
    address _job,
    address _token,
    uint256 _amount,
    address _receiver
  ) external;
}

/// @title  Keep3rJobFundableLiquidity contract
/// @notice Handles the funding of jobs through specific liquidity pairs
interface IKeep3rJobFundableLiquidity {
  // Events

  /// @notice Emitted when Keep3rJobFundableLiquidity#approveLiquidity function is called
  /// @param _liquidity The address of the liquidity pair being approved
  event LiquidityApproval(address _liquidity);

  /// @notice Emitted when Keep3rJobFundableLiquidity#revokeLiquidity function is called
  /// @param _liquidity The address of the liquidity pair being revoked
  event LiquidityRevocation(address _liquidity);

  /// @notice Emitted when IKeep3rJobFundableLiquidity#addLiquidityToJob function is called
  /// @param _job The address of the job to which liquidity will be added
  /// @param _liquidity The address of the liquidity being added
  /// @param _provider The user that calls the function
  /// @param _amount The amount of liquidity being added
  event LiquidityAddition(address indexed _job, address indexed _liquidity, address indexed _provider, uint256 _amount);

  /// @notice Emitted when IKeep3rJobFundableLiquidity#withdrawLiquidityFromJob function is called
  /// @param _job The address of the job of which liquidity will be withdrawn from
  /// @param _liquidity The address of the liquidity being withdrawn
  /// @param _receiver The receiver of the liquidity tokens
  /// @param _amount The amount of liquidity being withdrawn from the job
  event LiquidityWithdrawal(address indexed _job, address indexed _liquidity, address indexed _receiver, uint256 _amount);

  /// @notice Emitted when Keep3rJobFundableLiquidity#addLiquidityToJob function is called
  /// @param _job The address of the job whose credits will be updated
  /// @param _rewardedAt The time at which the job was last rewarded
  /// @param _currentCredits The current credits of the job
  /// @param _periodCredits The credits of the job for the current period
  event LiquidityCreditsReward(address indexed _job, uint256 _rewardedAt, uint256 _currentCredits, uint256 _periodCredits);

  /// @notice Emitted when Keep3rJobFundableLiquidity#forceLiquidityCreditsToJob function is called
  /// @param _job The address of the job whose credits will be updated
  /// @param _rewardedAt The time at which the job was last rewarded
  /// @param _currentCredits The current credits of the job
  event LiquidityCreditsForced(address indexed _job, uint256 _rewardedAt, uint256 _currentCredits);

  // Errors

  /// @notice Throws when the liquidity being approved has already been approved
  error LiquidityPairApproved();

  /// @notice Throws when the liquidity being removed has not been approved
  error LiquidityPairUnexistent();

  /// @notice Throws when trying to add liquidity to an unapproved pool
  error LiquidityPairUnapproved();

  /// @notice Throws when the job doesn't have the requested liquidity
  error JobLiquidityUnexistent();

  /// @notice Throws when trying to remove more liquidity than the job has
  error JobLiquidityInsufficient();

  /// @notice Throws when trying to add less liquidity than the minimum liquidity required
  error JobLiquidityLessThanMin();

  // Structs

  /// @notice Stores the tick information of the different liquidity pairs
  struct TickCache {
    int56 current; // Tracks the current tick
    int56 difference; // Stores the difference between the current tick and the last tick
    uint256 period; // Stores the period at which the last observation was made
  }

  // Variables

  /// @notice Lists liquidity pairs
  /// @return _list An array of addresses with all the approved liquidity pairs
  function approvedLiquidities() external view returns (address[] memory _list);

  /// @notice Amount of liquidity in a specified job
  /// @param _job The address of the job being checked
  /// @param _liquidity The address of the liquidity we are checking
  /// @return _amount Amount of liquidity in the specified job
  function liquidityAmount(address _job, address _liquidity) external view returns (uint256 _amount);

  /// @notice Last time the job was rewarded liquidity credits
  /// @param _job The address of the job being checked
  /// @return _timestamp Timestamp of the last time the job was rewarded liquidity credits
  function rewardedAt(address _job) external view returns (uint256 _timestamp);

  /// @notice Last time the job was worked
  /// @param _job The address of the job being checked
  /// @return _timestamp Timestamp of the last time the job was worked
  function workedAt(address _job) external view returns (uint256 _timestamp);

  // Methods

  /// @notice Returns the liquidity credits of a given job
  /// @param _job The address of the job of which we want to know the liquidity credits
  /// @return _amount The liquidity credits of a given job
  function jobLiquidityCredits(address _job) external view returns (uint256 _amount);

  /// @notice Returns the credits of a given job for the current period
  /// @param _job The address of the job of which we want to know the period credits
  /// @return _amount The credits the given job has at the current period
  function jobPeriodCredits(address _job) external view returns (uint256 _amount);

  /// @notice Calculates the total credits of a given job
  /// @param _job The address of the job of which we want to know the total credits
  /// @return _amount The total credits of the given job
  function totalJobCredits(address _job) external view returns (uint256 _amount);

  /// @notice Calculates how many credits should be rewarded periodically for a given liquidity amount
  /// @dev _periodCredits = underlying KP3Rs for given liquidity amount * rewardPeriod / inflationPeriod
  /// @param _liquidity The address of the liquidity to provide
  /// @param _amount The amount of liquidity to provide
  /// @return _periodCredits The amount of KP3R periodically minted for the given liquidity
  function quoteLiquidity(address _liquidity, uint256 _amount) external view returns (uint256 _periodCredits);

  /// @notice Observes the current state of the liquidity pair being observed and updates TickCache with the information
  /// @param _liquidity The address of the liquidity pair being observed
  /// @return _tickCache The updated TickCache
  function observeLiquidity(address _liquidity) external view returns (TickCache memory _tickCache);

  /// @notice Gifts liquidity credits to the specified job
  /// @param _job The address of the job being credited
  /// @param _amount The amount of liquidity credits to gift
  function forceLiquidityCreditsToJob(address _job, uint256 _amount) external;

  /// @notice Approve a liquidity pair for being accepted in future
  /// @param _liquidity The address of the liquidity accepted
  function approveLiquidity(address _liquidity) external;

  /// @notice Revoke a liquidity pair from being accepted in future
  /// @param _liquidity The liquidity no longer accepted
  function revokeLiquidity(address _liquidity) external;

  /// @notice Allows anyone to fund a job with liquidity
  /// @param _job The address of the job to assign liquidity to
  /// @param _liquidity The liquidity being added
  /// @param _amount The amount of liquidity tokens to add
  function addLiquidityToJob(
    address _job,
    address _liquidity,
    uint256 _amount
  ) external;

  /// @notice Unbond liquidity for a job
  /// @dev Can only be called by the job's owner
  /// @param _job The address of the job being unbonded from
  /// @param _liquidity The liquidity being unbonded
  /// @param _amount The amount of liquidity being removed
  function unbondLiquidityFromJob(
    address _job,
    address _liquidity,
    uint256 _amount
  ) external;

  /// @notice Withdraw liquidity from a job
  /// @param _job The address of the job being withdrawn from
  /// @param _liquidity The liquidity being withdrawn
  /// @param _receiver The address that will receive the withdrawn liquidity
  function withdrawLiquidityFromJob(
    address _job,
    address _liquidity,
    address _receiver
  ) external;
}

/// @title Keep3rJobManager contract
/// @notice Handles the addition and withdrawal of credits from a job
interface IKeep3rJobManager {
  // Events

  /// @notice Emitted when Keep3rJobManager#addJob is called
  /// @param _job The address of the job to add
  /// @param _jobOwner The job's owner
  event JobAddition(address indexed _job, address indexed _jobOwner);

  // Errors

  /// @notice Throws when trying to add a job that has already been added
  error JobAlreadyAdded();

  /// @notice Throws when the address that is trying to register as a keeper is already a keeper
  error AlreadyAKeeper();

  // Methods

  /// @notice Allows any caller to add a new job
  /// @param _job Address of the contract for which work should be performed
  function addJob(address _job) external;
}

/// @title Keep3rJobWorkable contract
/// @notice Handles the mechanisms jobs can pay keepers with along with the restrictions jobs can put on keepers before they can work on jobs
interface IKeep3rJobWorkable {
  // Events

  /// @notice Emitted when a keeper is validated before a job
  /// @param _gasLeft The amount of gas that the transaction has left at the moment of keeper validation
  event KeeperValidation(uint256 _gasLeft);

  /// @notice Emitted when a keeper works a job
  /// @param _credit The address of the asset in which the keeper is paid
  /// @param _job The address of the job the keeper has worked
  /// @param _keeper The address of the keeper that has worked the job
  /// @param _payment The amount that has been paid out to the keeper in exchange for working the job
  /// @param _gasLeft The amount of gas that the transaction has left at the moment of payment
  event KeeperWork(address indexed _credit, address indexed _job, address indexed _keeper, uint256 _payment, uint256 _gasLeft);

  // Errors

  /// @notice Throws if the address claiming to be a job is not in the list of approved jobs
  error JobUnapproved();

  /// @notice Throws if the amount of funds in the job is less than the payment that must be paid to the keeper that works that job
  error InsufficientFunds();

  // Methods

  /// @notice Confirms if the current keeper is registered
  /// @dev Can be used for general (non critical) functions
  /// @param _keeper The keeper being investigated
  /// @return _isKeeper Whether the address passed as a parameter is a keeper or not
  function isKeeper(address _keeper) external returns (bool _isKeeper);

  /// @notice Confirms if the current keeper is registered and has a minimum bond of any asset.
  /// @dev Should be used for protected functions
  /// @param _keeper The keeper to check
  /// @param _bond The bond token being evaluated
  /// @param _minBond The minimum amount of bonded tokens
  /// @param _earned The minimum funds earned in the keepers lifetime
  /// @param _age The minimum keeper age required
  /// @return _isBondedKeeper Whether the `_keeper` meets the given requirements
  function isBondedKeeper(
    address _keeper,
    address _bond,
    uint256 _minBond,
    uint256 _earned,
    uint256 _age
  ) external returns (bool _isBondedKeeper);

  /// @notice Implemented by jobs to show that a keeper performed work
  /// @dev Automatically calculates the payment for the keeper and pays the keeper with bonded KP3R
  /// @param _keeper Address of the keeper that performed the work
  function worked(address _keeper) external;

  /// @notice Implemented by jobs to show that a keeper performed work
  /// @dev Pays the keeper that performs the work with KP3R
  /// @param _keeper Address of the keeper that performed the work
  /// @param _payment The reward that should be allocated for the job
  function bondedPayment(address _keeper, uint256 _payment) external;

  /// @notice Implemented by jobs to show that a keeper performed work
  /// @dev Pays the keeper that performs the work with a specific token
  /// @param _token The asset being awarded to the keeper
  /// @param _keeper Address of the keeper that performed the work
  /// @param _amount The reward that should be allocated
  function directTokenPayment(
    address _token,
    address _keeper,
    uint256 _amount
  ) external;
}

/// @title Keep3rJobOwnership contract
/// @notice Handles the ownership of the jobs
interface IKeep3rJobOwnership {
  // Events

  /// @notice Emitted when Keep3rJobOwnership#changeJobOwnership is called
  /// @param _job The address of the job proposed to have a change of owner
  /// @param _owner The current owner of the job
  /// @param _pendingOwner The new address proposed to be the owner of the job
  event JobOwnershipChange(address indexed _job, address indexed _owner, address indexed _pendingOwner);

  /// @notice Emitted when Keep3rJobOwnership#JobOwnershipAssent is called
  /// @param _job The address of the job which the proposed owner will now own
  /// @param _previousOwner The previous owner of the job
  /// @param _newOwner The new owner of the job
  event JobOwnershipAssent(address indexed _job, address indexed _previousOwner, address indexed _newOwner);

  // Errors

  /// @notice Throws when the caller of the function is not the job owner
  error OnlyJobOwner();

  /// @notice Throws when the caller of the function is not the pending job owner
  error OnlyPendingJobOwner();

  // Variables

  /// @notice Maps the job to the owner of the job
  /// @param _job The address of the job
  /// @return _owner The address of the owner of the job
  function jobOwner(address _job) external view returns (address _owner);

  /// @notice Maps the job to its pending owner
  /// @param _job The address of the job
  /// @return _pendingOwner The address of the pending owner of the job
  function jobPendingOwner(address _job) external view returns (address _pendingOwner);

  // Methods

  /// @notice Proposes a new address to be the owner of the job
  /// @param _job The address of the job
  /// @param _newOwner The address of the proposed new owner
  function changeJobOwnership(address _job, address _newOwner) external;

  /// @notice The proposed address accepts to be the owner of the job
  /// @param _job The address of the job
  function acceptJobOwnership(address _job) external;
}

/// @title Keep3rJobMigration contract
/// @notice Handles the migration process of jobs to different addresses
interface IKeep3rJobMigration {
  // Events

  /// @notice Emitted when Keep3rJobMigration#migrateJob function is called
  /// @param _fromJob The address of the job that requests to migrate
  /// @param _toJob The address at which the job requests to migrate
  event JobMigrationRequested(address indexed _fromJob, address _toJob);

  /// @notice Emitted when Keep3rJobMigration#acceptJobMigration function is called
  /// @param _fromJob The address of the job that requested to migrate
  /// @param _toJob The address at which the job had requested to migrate
  event JobMigrationSuccessful(address _fromJob, address indexed _toJob);

  // Errors

  /// @notice Throws when the address of the job that requests to migrate wants to migrate to its same address
  error JobMigrationImpossible();

  /// @notice Throws when the _toJob address differs from the address being tracked in the pendingJobMigrations mapping
  error JobMigrationUnavailable();

  /// @notice Throws when cooldown between migrations has not yet passed
  error JobMigrationLocked();

  // Variables

  /// @notice Maps the jobs that have requested a migration to the address they have requested to migrate to
  /// @return _toJob The address to which the job has requested to migrate to
  function pendingJobMigrations(address _fromJob) external view returns (address _toJob);

  // Methods

  /// @notice Initializes the migration process for a job by adding the request to the pendingJobMigrations mapping
  /// @param _fromJob The address of the job that is requesting to migrate
  /// @param _toJob The address at which the job is requesting to migrate
  function migrateJob(address _fromJob, address _toJob) external;

  /// @notice Completes the migration process for a job
  /// @dev Unbond/withdraw process doesn't get migrated
  /// @param _fromJob The address of the job that requested to migrate
  /// @param _toJob The address to which the job wants to migrate to
  function acceptJobMigration(address _fromJob, address _toJob) external;
}

/// @title Keep3rJobDisputable contract
/// @notice Handles the actions that can be taken on a disputed job
interface IKeep3rJobDisputable is IKeep3rJobFundableCredits, IKeep3rJobFundableLiquidity {
  // Events

  /// @notice Emitted when Keep3rJobDisputable#slashTokenFromJob is called
  /// @param _job The address of the job from which the token will be slashed
  /// @param _token The address of the token being slashed
  /// @param _slasher The user that slashes the token
  /// @param _amount The amount of the token being slashed
  event JobSlashToken(address indexed _job, address _token, address indexed _slasher, uint256 _amount);

  /// @notice Emitted when Keep3rJobDisputable#slashLiquidityFromJob is called
  /// @param _job The address of the job from which the liquidity will be slashed
  /// @param _liquidity The address of the liquidity being slashed
  /// @param _slasher The user that slashes the liquidity
  /// @param _amount The amount of the liquidity being slashed
  event JobSlashLiquidity(address indexed _job, address _liquidity, address indexed _slasher, uint256 _amount);

  // Errors

  /// @notice Throws when the token trying to be slashed doesn't exist
  error JobTokenUnexistent();

  /// @notice Throws when someone tries to slash more tokens than the job has
  error JobTokenInsufficient();

  // Methods

  /// @notice Allows governance or slasher to slash a job specific token
  /// @param _job The address of the job from which the token will be slashed
  /// @param _token The address of the token that will be slashed
  /// @param _amount The amount of the token that will be slashed
  function slashTokenFromJob(
    address _job,
    address _token,
    uint256 _amount
  ) external;

  /// @notice Allows governance or a slasher to slash liquidity from a job
  /// @param _job The address being slashed
  /// @param _liquidity The address of the liquidity that will be slashed
  /// @param _amount The amount of liquidity that will be slashed
  function slashLiquidityFromJob(
    address _job,
    address _liquidity,
    uint256 _amount
  ) external;
}

// solhint-disable-next-line no-empty-blocks
interface IKeep3rJobs is IKeep3rJobOwnership, IKeep3rJobDisputable, IKeep3rJobMigration, IKeep3rJobManager, IKeep3rJobWorkable {

}

File 16 of 39 : 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 17 of 39 : 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 39 : 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 19 of 39 : Math.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

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

File 20 of 39 : 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 21 of 39 : IKeep3rAccountance.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

/// @title Keep3rDisputable contract
/// @notice Disputes keepers, or if they're already disputed, it can resolve the case
/// @dev Argument `bonding` can be the address of either a token or a liquidity
interface IKeep3rAccountance {
  // Events

  /// @notice Emitted when the bonding process of a new keeper begins
  /// @param _keeper The caller of Keep3rKeeperFundable#bond function
  /// @param _bonding The asset the keeper has bonded
  /// @param _amount The amount the keeper has bonded
  event Bonding(address indexed _keeper, address indexed _bonding, uint256 _amount);

  /// @notice Emitted when a keeper or job begins the unbonding process to withdraw the funds
  /// @param _keeperOrJob The keeper or job that began the unbonding process
  /// @param _unbonding The liquidity pair or asset being unbonded
  /// @param _amount The amount being unbonded
  event Unbonding(address indexed _keeperOrJob, address indexed _unbonding, uint256 _amount);

  // Variables

  /// @notice Tracks the total KP3R earnings of a keeper since it started working
  /// @param _keeper The address of the keeper
  /// @return _workCompleted Total KP3R earnings of a keeper since it started working
  function workCompleted(address _keeper) external view returns (uint256 _workCompleted);

  /// @notice Tracks when a keeper was first registered
  /// @param _keeper The address of the keeper
  /// @return timestamp The time at which the keeper was first registered
  function firstSeen(address _keeper) external view returns (uint256 timestamp);

  /// @notice Tracks if a keeper or job has a pending dispute
  /// @param _keeperOrJob The address of the keeper or job
  /// @return _disputed Whether a keeper or job has a pending dispute
  function disputes(address _keeperOrJob) external view returns (bool _disputed);

  /// @notice Tracks how much a keeper has bonded of a certain token
  /// @param _keeper The address of the keeper
  /// @param _bond The address of the token being bonded
  /// @return _bonds Amount of a certain token that a keeper has bonded
  function bonds(address _keeper, address _bond) external view returns (uint256 _bonds);

  /// @notice The current token credits available for a job
  /// @param _job The address of the job
  /// @param _token The address of the token bonded
  /// @return _amount The amount of token credits available for a job
  function jobTokenCredits(address _job, address _token) external view returns (uint256 _amount);

  /// @notice Tracks the amount of assets deposited in pending bonds
  /// @param _keeper The address of the keeper
  /// @param _bonding The address of the token being bonded
  /// @return _pendingBonds Amount of a certain asset a keeper has unbonding
  function pendingBonds(address _keeper, address _bonding) external view returns (uint256 _pendingBonds);

  /// @notice Tracks when a bonding for a keeper can be activated
  /// @param _keeper The address of the keeper
  /// @param _bonding The address of the token being bonded
  /// @return _timestamp Time at which the bonding for a keeper can be activated
  function canActivateAfter(address _keeper, address _bonding) external view returns (uint256 _timestamp);

  /// @notice Tracks when keeper bonds are ready to be withdrawn
  /// @param _keeper The address of the keeper
  /// @param _bonding The address of the token being unbonded
  /// @return _timestamp Time at which the keeper bonds are ready to be withdrawn
  function canWithdrawAfter(address _keeper, address _bonding) external view returns (uint256 _timestamp);

  /// @notice Tracks how much keeper bonds are to be withdrawn
  /// @param _keeper The address of the keeper
  /// @param _bonding The address of the token being unbonded
  /// @return _pendingUnbonds The amount of keeper bonds that are to be withdrawn
  function pendingUnbonds(address _keeper, address _bonding) external view returns (uint256 _pendingUnbonds);

  /// @notice Checks whether the address has ever bonded an asset
  /// @param _keeper The address of the keeper
  /// @return _hasBonded Whether the address has ever bonded an asset
  function hasBonded(address _keeper) external view returns (bool _hasBonded);

  // Methods

  /// @notice Lists all jobs
  /// @return _jobList Array with all the jobs in _jobs
  function jobs() external view returns (address[] memory _jobList);

  /// @notice Lists all keepers
  /// @return _keeperList Array with all the keepers in _keepers
  function keepers() external view returns (address[] memory _keeperList);

  // Errors

  /// @notice Throws when an address is passed as a job, but that address is not a job
  error JobUnavailable();

  /// @notice Throws when an action that requires an undisputed job is applied on a disputed job
  error JobDisputed();
}

File 22 of 39 : IKeep3rHelper.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

/// @title Keep3rHelper contract
/// @notice Contains all the helper functions used throughout the different files.

interface IKeep3rHelper {
  // Errors

  /// @notice Throws when none of the tokens in the liquidity pair is KP3R
  error LiquidityPairInvalid();

  // Methods
  // solhint-enable func-name-mixedcase

  /// @notice Calculates the amount of KP3R that corresponds to the ETH passed into the function
  /// @dev This function allows us to calculate how much KP3R we should pay to a keeper for things expressed in ETH, like gas
  /// @param _eth The amount of ETH
  /// @return _amountOut The amount of KP3R
  function quote(uint256 _eth) external view returns (uint256 _amountOut);

  /// @notice Returns the amount of KP3R the keeper has bonded
  /// @param _keeper The address of the keeper to check
  /// @return _amountBonded The amount of KP3R the keeper has bonded
  function bonds(address _keeper) external view returns (uint256 _amountBonded);

  /// @notice Calculates the reward (in KP3R) that corresponds to a keeper for using gas
  /// @param _keeper The address of the keeper to check
  /// @param _gasUsed The amount of gas used that will be rewarded
  /// @return _kp3r The amount of KP3R that should be awarded to the keeper
  function getRewardAmountFor(address _keeper, uint256 _gasUsed) external view returns (uint256 _kp3r);

  /// @notice Calculates the boost in the reward given to a keeper based on the amount of KP3R that keeper has bonded
  /// @param _bonds The amount of KP3R tokens bonded by the keeper
  /// @return _rewardBoost The reward boost that corresponds to the keeper
  function getRewardBoostFor(uint256 _bonds) external view returns (uint256 _rewardBoost);

  /// @notice Calculates the reward (in KP3R) that corresponds to tx.origin for using gas
  /// @param _gasUsed The amount of gas used that will be rewarded
  /// @return _amount The amount of KP3R that should be awarded to tx.origin
  function getRewardAmount(uint256 _gasUsed) external view returns (uint256 _amount);

  /// @notice Given a pool address, returns the underlying tokens of the pair
  /// @param _pool Address of the correspondant pool
  /// @return _token0 Address of the first token of the pair
  /// @return _token1 Address of the second token of the pair
  function getPoolTokens(address _pool) external view returns (address _token0, address _token1);

  /// @notice Defines the order of the tokens in the pair for twap calculations
  /// @param _pool Address of the correspondant pool
  /// @return _isKP3RToken0 Boolean indicating the order of the tokens in the pair
  function isKP3RToken0(address _pool) external view returns (bool _isKP3RToken0);

  /// @notice Given an array of secondsAgo, returns UniswapV3 pool cumulatives at that moment
  /// @param _pool Address of the pool to observe
  /// @param _secondsAgo Array with time references to observe
  /// @return _tickCumulative1 Cummulative sum of ticks until first time reference
  /// @return _tickCumulative2 Cummulative sum of ticks until second time reference
  /// @return _success Boolean indicating if the observe call was succesfull
  function observe(address _pool, uint32[] memory _secondsAgo)
    external
    view
    returns (
      int56 _tickCumulative1,
      int56 _tickCumulative2,
      bool _success
    );

  /// @notice Get multiplier, quote, and extra, in order to calculate keeper payment
  /// @param _bonds Amount of bonded KP3R owned by the keeper
  /// @return _boost Multiplier per gas unit. Takes into account the base fee and the amount of bonded KP3R
  /// @return _oneEthQuote Amount of KP3R tokens equivalent to 1 ETH
  /// @return _extra Amount of extra gas that should be added to the gas spent
  function getPaymentParams(uint256 _bonds)
    external
    view
    returns (
      uint256 _boost,
      uint256 _oneEthQuote,
      uint256 _extra
    );

  /// @notice Given a tick and a liquidity amount, calculates the underlying KP3R tokens
  /// @param _liquidityAmount Amount of liquidity to be converted
  /// @param _tickDifference Tick value used to calculate the quote
  /// @param _timeInterval Time value used to calculate the quote
  /// @return _kp3rAmount Amount of KP3R tokens underlying on the given liquidity
  function getKP3RsAtTick(
    uint256 _liquidityAmount,
    int56 _tickDifference,
    uint256 _timeInterval
  ) external pure returns (uint256 _kp3rAmount);

  /// @notice Given a tick and a token amount, calculates the output in correspondant token
  /// @param _baseAmount Amount of token to be converted
  /// @param _tickDifference Tick value used to calculate the quote
  /// @param _timeInterval Time value used to calculate the quote
  /// @return _quoteAmount Amount of credits deserved for the baseAmount at the tick value
  function getQuoteAtTick(
    uint128 _baseAmount,
    int56 _tickDifference,
    uint256 _timeInterval
  ) external pure returns (uint256 _quoteAmount);
}

File 23 of 39 : IKeep3rParameters.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './IBaseErrors.sol';

/// @title Keep3rParameters contract
/// @notice Handles and sets all the required parameters for Keep3r

interface IKeep3rParameters is IBaseErrors {
  // Events

  /// @notice Emitted when the Keep3rHelper address is changed
  /// @param _keep3rHelper The address of Keep3rHelper's contract
  event Keep3rHelperChange(address _keep3rHelper);

  /// @notice Emitted when the Keep3rV1 address is changed
  /// @param _keep3rV1 The address of Keep3rV1's contract
  event Keep3rV1Change(address _keep3rV1);

  /// @notice Emitted when the Keep3rV1Proxy address is changed
  /// @param _keep3rV1Proxy The address of Keep3rV1Proxy's contract
  event Keep3rV1ProxyChange(address _keep3rV1Proxy);

  /// @notice Emitted when the KP3R-WETH pool address is changed
  /// @param _kp3rWethPool The address of the KP3R-WETH pool
  event Kp3rWethPoolChange(address _kp3rWethPool);

  /// @notice Emitted when bondTime is changed
  /// @param _bondTime The new bondTime
  event BondTimeChange(uint256 _bondTime);

  /// @notice Emitted when _liquidityMinimum is changed
  /// @param _liquidityMinimum The new _liquidityMinimum
  event LiquidityMinimumChange(uint256 _liquidityMinimum);

  /// @notice Emitted when _unbondTime is changed
  /// @param _unbondTime The new _unbondTime
  event UnbondTimeChange(uint256 _unbondTime);

  /// @notice Emitted when _rewardPeriodTime is changed
  /// @param _rewardPeriodTime The new _rewardPeriodTime
  event RewardPeriodTimeChange(uint256 _rewardPeriodTime);

  /// @notice Emitted when the inflationPeriod is changed
  /// @param _inflationPeriod The new inflationPeriod
  event InflationPeriodChange(uint256 _inflationPeriod);

  /// @notice Emitted when the fee is changed
  /// @param _fee The new token credits fee
  event FeeChange(uint256 _fee);

  // Variables

  /// @notice Address of Keep3rHelper's contract
  /// @return _keep3rHelper The address of Keep3rHelper's contract
  function keep3rHelper() external view returns (address _keep3rHelper);

  /// @notice Address of Keep3rV1's contract
  /// @return _keep3rV1 The address of Keep3rV1's contract
  function keep3rV1() external view returns (address _keep3rV1);

  /// @notice Address of Keep3rV1Proxy's contract
  /// @return _keep3rV1Proxy The address of Keep3rV1Proxy's contract
  function keep3rV1Proxy() external view returns (address _keep3rV1Proxy);

  /// @notice Address of the KP3R-WETH pool
  /// @return _kp3rWethPool The address of KP3R-WETH pool
  function kp3rWethPool() external view returns (address _kp3rWethPool);

  /// @notice The amount of time required to pass after a keeper has bonded assets for it to be able to activate
  /// @return _days The required bondTime in days
  function bondTime() external view returns (uint256 _days);

  /// @notice The amount of time required to pass before a keeper can unbond what he has bonded
  /// @return _days The required unbondTime in days
  function unbondTime() external view returns (uint256 _days);

  /// @notice The minimum amount of liquidity required to fund a job per liquidity
  /// @return _amount The minimum amount of liquidity in KP3R
  function liquidityMinimum() external view returns (uint256 _amount);

  /// @notice The amount of time between each scheduled credits reward given to a job
  /// @return _days The reward period in days
  function rewardPeriodTime() external view returns (uint256 _days);

  /// @notice The inflation period is the denominator used to regulate the emission of KP3R
  /// @return _period The denominator used to regulate the emission of KP3R
  function inflationPeriod() external view returns (uint256 _period);

  /// @notice The fee to be sent to governance when a user adds liquidity to a job
  /// @return _amount The fee amount to be sent to governance when a user adds liquidity to a job
  function fee() external view returns (uint256 _amount);

  // Errors

  /// @notice Throws if the reward period is less than the minimum reward period time
  error MinRewardPeriod();

  /// @notice Throws if either a job or a keeper is disputed
  error Disputed();

  /// @notice Throws if there are no bonded assets
  error BondsUnexistent();

  /// @notice Throws if the time required to bond an asset has not passed yet
  error BondsLocked();

  /// @notice Throws if there are no bonds to withdraw
  error UnbondsUnexistent();

  /// @notice Throws if the time required to withdraw the bonds has not passed yet
  error UnbondsLocked();

  // Methods

  /// @notice Sets the Keep3rHelper address
  /// @param _keep3rHelper The Keep3rHelper address
  function setKeep3rHelper(address _keep3rHelper) external;

  /// @notice Sets the Keep3rV1 address
  /// @param _keep3rV1 The Keep3rV1 address
  function setKeep3rV1(address _keep3rV1) external;

  /// @notice Sets the Keep3rV1Proxy address
  /// @param _keep3rV1Proxy The Keep3rV1Proxy address
  function setKeep3rV1Proxy(address _keep3rV1Proxy) external;

  /// @notice Sets the KP3R-WETH pool address
  /// @param _kp3rWethPool The KP3R-WETH pool address
  function setKp3rWethPool(address _kp3rWethPool) external;

  /// @notice Sets the bond time required to activate as a keeper
  /// @param _bond The new bond time
  function setBondTime(uint256 _bond) external;

  /// @notice Sets the unbond time required unbond what has been bonded
  /// @param _unbond The new unbond time
  function setUnbondTime(uint256 _unbond) external;

  /// @notice Sets the minimum amount of liquidity required to fund a job
  /// @param _liquidityMinimum The new minimum amount of liquidity
  function setLiquidityMinimum(uint256 _liquidityMinimum) external;

  /// @notice Sets the time required to pass between rewards for jobs
  /// @param _rewardPeriodTime The new amount of time required to pass between rewards
  function setRewardPeriodTime(uint256 _rewardPeriodTime) external;

  /// @notice Sets the new inflation period
  /// @param _inflationPeriod The new inflation period
  function setInflationPeriod(uint256 _inflationPeriod) external;

  /// @notice Sets the new fee
  /// @param _fee The new fee
  function setFee(uint256 _fee) external;
}

File 24 of 39 : IBaseErrors.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.4 <0.9.0;

interface IBaseErrors {
  /// @notice Throws if a variable is assigned to the zero address
  error ZeroAddress();
}

File 25 of 39 : IKeep3rRoles.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

/// @title Keep3rRoles contract
/// @notice Manages the Keep3r specific roles
interface IKeep3rRoles {
  // Events

  /// @notice Emitted when a slasher is added
  /// @param _slasher Address of the added slasher
  event SlasherAdded(address _slasher);

  /// @notice Emitted when a slasher is removed
  /// @param _slasher Address of the removed slasher
  event SlasherRemoved(address _slasher);

  /// @notice Emitted when a disputer is added
  /// @param _disputer Address of the added disputer
  event DisputerAdded(address _disputer);

  /// @notice Emitted when a disputer is removed
  /// @param _disputer Address of the removed disputer
  event DisputerRemoved(address _disputer);

  // Variables

  /// @notice Tracks whether the address is a slasher or not
  /// @param _slasher Address being checked as a slasher
  /// @return _isSlasher Whether the address is a slasher or not
  function slashers(address _slasher) external view returns (bool _isSlasher);

  /// @notice Tracks whether the address is a disputer or not
  /// @param _disputer Address being checked as a disputer
  /// @return _isDisputer Whether the address is a disputer or not
  function disputers(address _disputer) external view returns (bool _isDisputer);

  // Errors

  /// @notice Throws if the address is already a registered slasher
  error SlasherExistent();

  /// @notice Throws if caller is not a registered slasher
  error SlasherUnexistent();

  /// @notice Throws if the address is already a registered disputer
  error DisputerExistent();

  /// @notice Throws if caller is not a registered disputer
  error DisputerUnexistent();

  /// @notice Throws if the msg.sender is not a slasher or is not a part of governance
  error OnlySlasher();

  /// @notice Throws if the msg.sender is not a disputer or is not a part of governance
  error OnlyDisputer();

  // Methods

  /// @notice Registers a slasher by updating the slashers mapping
  function addSlasher(address _slasher) external;

  /// @notice Removes a slasher by updating the slashers mapping
  function removeSlasher(address _slasher) external;

  /// @notice Registers a disputer by updating the disputers mapping
  function addDisputer(address _disputer) external;

  /// @notice Removes a disputer by updating the disputers mapping
  function removeDisputer(address _disputer) external;
}

File 26 of 39 : Governable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '../../interfaces/peripherals/IGovernable.sol';

abstract contract Governable is IGovernable {
  /// @inheritdoc IGovernable
  address public override governance;

  /// @inheritdoc IGovernable
  address public override pendingGovernance;

  constructor(address _governance) {
    if (_governance == address(0)) revert NoGovernanceZeroAddress();
    governance = _governance;
  }

  /// @inheritdoc IGovernable
  function setGovernance(address _governance) external override onlyGovernance {
    pendingGovernance = _governance;
    emit GovernanceProposal(_governance);
  }

  /// @inheritdoc IGovernable
  function acceptGovernance() external override onlyPendingGovernance {
    governance = pendingGovernance;
    delete pendingGovernance;
    emit GovernanceSet(governance);
  }

  /// @notice Functions with this modifier can only be called by governance
  modifier onlyGovernance {
    if (msg.sender != governance) revert OnlyGovernance();
    _;
  }

  /// @notice Functions with this modifier can only be called by pendingGovernance
  modifier onlyPendingGovernance {
    if (msg.sender != pendingGovernance) revert OnlyPendingGovernance();
    _;
  }
}

File 27 of 39 : IGovernable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

/// @title Governable contract
/// @notice Manages the governance role
interface IGovernable {
  // Events

  /// @notice Emitted when pendingGovernance accepts to be governance
  /// @param _governance Address of the new governance
  event GovernanceSet(address _governance);

  /// @notice Emitted when a new governance is proposed
  /// @param _pendingGovernance Address that is proposed to be the new governance
  event GovernanceProposal(address _pendingGovernance);

  // Errors

  /// @notice Throws if the caller of the function is not governance
  error OnlyGovernance();

  /// @notice Throws if the caller of the function is not pendingGovernance
  error OnlyPendingGovernance();

  /// @notice Throws if trying to set governance to zero address
  error NoGovernanceZeroAddress();

  // Variables

  /// @notice Stores the governance address
  /// @return _governance The governance addresss
  function governance() external view returns (address _governance);

  /// @notice Stores the pendingGovernance address
  /// @return _pendingGovernance The pendingGovernance addresss
  function pendingGovernance() external view returns (address _pendingGovernance);

  // Methods

  /// @notice Proposes a new address to be governance
  /// @param _governance The address being proposed as the new governance
  function setGovernance(address _governance) external;

  /// @notice Changes the governance from the current governance to the previously proposed address
  function acceptGovernance() external;
}

File 28 of 39 : 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 29 of 39 : IPairManager.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';

/// @title  Pair Manager interface
/// @notice Generic interface for Keep3r liquidity pools (kLP)
interface IPairManager is IERC20Metadata {
  /// @notice Address of the factory from which the pair manager was created
  /// @return _factory The address of the PairManager Factory
  function factory() external view returns (address _factory);

  /// @notice Address of the pool from which the Keep3r pair manager will interact with
  /// @return _pool The address of the pool
  function pool() external view returns (address _pool);

  /// @notice Token0 of the pool
  /// @return _token0 The address of token0
  function token0() external view returns (address _token0);

  /// @notice Token1 of the pool
  /// @return _token1 The address of token1
  function token1() external view returns (address _token1);
}

File 30 of 39 : FullMath.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.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
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 mulDiv(
    uint256 a,
    uint256 b,
    uint256 denominator
  ) internal pure returns (uint256 result) {
    unchecked {
      // 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);
        assembly {
          result := div(prod0, denominator)
        }
        return result;
      }

      // Make sure the result is less than 2**256.
      // Also prevents denominator == 0
      require(denominator > 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 + 1) & denominator;
      // 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)
      }
      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 mulDivRoundingUp(
    uint256 a,
    uint256 b,
    uint256 denominator
  ) internal pure returns (uint256 result) {
    unchecked {
      result = mulDiv(a, b, denominator);
      if (mulmod(a, b, denominator) > 0) {
        require(result < type(uint256).max);
        result++;
      }
    }
  }
}

File 31 of 39 : 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 32 of 39 : IKeep3rDisputable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

/// @title Keep3rDisputable contract
/// @notice Creates/resolves disputes for jobs or keepers
///         A disputed keeper is slashable and is not able to bond, activate, withdraw or receive direct payments
///         A disputed job is slashable and is not able to pay the keepers, withdraw tokens or to migrate
interface IKeep3rDisputable {
  /// @notice Emitted when a keeper or a job is disputed
  /// @param _jobOrKeeper The address of the disputed keeper/job
  /// @param _disputer The user that called the function and disputed the keeper
  event Dispute(address indexed _jobOrKeeper, address indexed _disputer);

  /// @notice Emitted when a dispute is resolved
  /// @param _jobOrKeeper The address of the disputed keeper/job
  /// @param _resolver The user that called the function and resolved the dispute
  event Resolve(address indexed _jobOrKeeper, address indexed _resolver);

  /// @notice Throws when a job or keeper is already disputed
  error AlreadyDisputed();

  /// @notice Throws when a job or keeper is not disputed and someone tries to resolve the dispute
  error NotDisputed();

  /// @notice Allows governance to create a dispute for a given keeper/job
  /// @param _jobOrKeeper The address in dispute
  function dispute(address _jobOrKeeper) external;

  /// @notice Allows governance to resolve a dispute on a keeper/job
  /// @param _jobOrKeeper The address cleared
  function resolve(address _jobOrKeeper) external;
}

File 33 of 39 : Keep3rJobMigration.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '../../../interfaces/peripherals/IKeep3rJobs.sol';
import './Keep3rJobFundableCredits.sol';
import './Keep3rJobFundableLiquidity.sol';

abstract contract Keep3rJobMigration is IKeep3rJobMigration, Keep3rJobFundableCredits, Keep3rJobFundableLiquidity {
  using EnumerableSet for EnumerableSet.AddressSet;

  uint256 internal constant _MIGRATION_COOLDOWN = 1 minutes;

  /// @inheritdoc IKeep3rJobMigration
  mapping(address => address) public override pendingJobMigrations;
  mapping(address => mapping(address => uint256)) internal _migrationCreatedAt;

  /// @inheritdoc IKeep3rJobMigration
  function migrateJob(address _fromJob, address _toJob) external override onlyJobOwner(_fromJob) {
    if (_fromJob == _toJob) revert JobMigrationImpossible();

    pendingJobMigrations[_fromJob] = _toJob;
    _migrationCreatedAt[_fromJob][_toJob] = block.timestamp;

    emit JobMigrationRequested(_fromJob, _toJob);
  }

  /// @inheritdoc IKeep3rJobMigration
  function acceptJobMigration(address _fromJob, address _toJob) external override onlyJobOwner(_toJob) {
    if (disputes[_fromJob] || disputes[_toJob]) revert JobDisputed();
    if (pendingJobMigrations[_fromJob] != _toJob) revert JobMigrationUnavailable();
    if (block.timestamp < _migrationCreatedAt[_fromJob][_toJob] + _MIGRATION_COOLDOWN) revert JobMigrationLocked();

    // force job credits update for both jobs
    _settleJobAccountance(_fromJob);
    _settleJobAccountance(_toJob);

    // migrate tokens
    while (_jobTokens[_fromJob].length() > 0) {
      address _tokenToMigrate = _jobTokens[_fromJob].at(0);
      jobTokenCredits[_toJob][_tokenToMigrate] += jobTokenCredits[_fromJob][_tokenToMigrate];
      delete jobTokenCredits[_fromJob][_tokenToMigrate];
      _jobTokens[_fromJob].remove(_tokenToMigrate);
      _jobTokens[_toJob].add(_tokenToMigrate);
    }

    // migrate liquidities
    while (_jobLiquidities[_fromJob].length() > 0) {
      address _liquidity = _jobLiquidities[_fromJob].at(0);

      liquidityAmount[_toJob][_liquidity] += liquidityAmount[_fromJob][_liquidity];
      delete liquidityAmount[_fromJob][_liquidity];

      _jobLiquidities[_toJob].add(_liquidity);
      _jobLiquidities[_fromJob].remove(_liquidity);
    }

    // migrate job balances
    _jobPeriodCredits[_toJob] += _jobPeriodCredits[_fromJob];
    delete _jobPeriodCredits[_fromJob];

    _jobLiquidityCredits[_toJob] += _jobLiquidityCredits[_fromJob];
    delete _jobLiquidityCredits[_fromJob];

    // stop _fromJob from being a job
    delete rewardedAt[_fromJob];
    _jobs.remove(_fromJob);

    // delete unused data slots
    delete jobOwner[_fromJob];
    delete jobPendingOwner[_fromJob];
    delete _migrationCreatedAt[_fromJob][_toJob];
    delete pendingJobMigrations[_fromJob];

    emit JobMigrationSuccessful(_fromJob, _toJob);
  }
}

File 34 of 39 : Keep3rKeeperDisputable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import './Keep3rKeeperFundable.sol';
import '../Keep3rDisputable.sol';
import '../../../interfaces/external/IKeep3rV1.sol';
import '../../../interfaces/peripherals/IKeep3rKeepers.sol';

abstract contract Keep3rKeeperDisputable is IKeep3rKeeperDisputable, Keep3rDisputable, Keep3rKeeperFundable {
  using EnumerableSet for EnumerableSet.AddressSet;
  using SafeERC20 for IERC20;

  /// @inheritdoc IKeep3rKeeperDisputable
  function slash(
    address _keeper,
    address _bonded,
    uint256 _bondAmount,
    uint256 _unbondAmount
  ) public override onlySlasher {
    if (!disputes[_keeper]) revert NotDisputed();
    _slash(_keeper, _bonded, _bondAmount, _unbondAmount);
    emit KeeperSlash(_keeper, msg.sender, _bondAmount + _unbondAmount);
  }

  /// @inheritdoc IKeep3rKeeperDisputable
  function revoke(address _keeper) external override onlySlasher {
    if (!disputes[_keeper]) revert NotDisputed();
    _keepers.remove(_keeper);
    _slash(_keeper, keep3rV1, bonds[_keeper][keep3rV1], pendingUnbonds[_keeper][keep3rV1]);
    emit KeeperRevoke(_keeper, msg.sender);
  }

  function _slash(
    address _keeper,
    address _bonded,
    uint256 _bondAmount,
    uint256 _unbondAmount
  ) internal {
    if (_bonded != keep3rV1) {
      try IERC20(_bonded).transfer(governance, _bondAmount + _unbondAmount) returns (bool) {} catch (bytes memory) {}
    }
    bonds[_keeper][_bonded] -= _bondAmount;
    pendingUnbonds[_keeper][_bonded] -= _unbondAmount;
  }
}

File 35 of 39 : Keep3rKeeperFundable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '../Keep3rAccountance.sol';
import '../Keep3rParameters.sol';
import '../../../interfaces/peripherals/IKeep3rKeepers.sol';

import '../../../interfaces/external/IKeep3rV1.sol';
import '../../../interfaces/external/IKeep3rV1Proxy.sol';

import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';

abstract contract Keep3rKeeperFundable is IKeep3rKeeperFundable, ReentrancyGuard, Keep3rParameters {
  using EnumerableSet for EnumerableSet.AddressSet;
  using SafeERC20 for IERC20;

  /// @inheritdoc IKeep3rKeeperFundable
  function bond(address _bonding, uint256 _amount) external override nonReentrant {
    if (disputes[msg.sender]) revert Disputed();
    if (_jobs.contains(msg.sender)) revert AlreadyAJob();
    canActivateAfter[msg.sender][_bonding] = block.timestamp + bondTime;

    uint256 _before = IERC20(_bonding).balanceOf(address(this));
    IERC20(_bonding).safeTransferFrom(msg.sender, address(this), _amount);
    _amount = IERC20(_bonding).balanceOf(address(this)) - _before;

    hasBonded[msg.sender] = true;
    pendingBonds[msg.sender][_bonding] += _amount;

    emit Bonding(msg.sender, _bonding, _amount);
  }

  /// @inheritdoc IKeep3rKeeperFundable
  function activate(address _bonding) external override {
    if (disputes[msg.sender]) revert Disputed();
    if (canActivateAfter[msg.sender][_bonding] == 0) revert BondsUnexistent();
    if (canActivateAfter[msg.sender][_bonding] >= block.timestamp) revert BondsLocked();

    delete canActivateAfter[msg.sender][_bonding];

    uint256 _amount = _activate(msg.sender, _bonding);
    emit Activation(msg.sender, _bonding, _amount);
  }

  /// @inheritdoc IKeep3rKeeperFundable
  function unbond(address _bonding, uint256 _amount) external override {
    canWithdrawAfter[msg.sender][_bonding] = block.timestamp + unbondTime;
    bonds[msg.sender][_bonding] -= _amount;
    pendingUnbonds[msg.sender][_bonding] += _amount;

    emit Unbonding(msg.sender, _bonding, _amount);
  }

  /// @inheritdoc IKeep3rKeeperFundable
  function withdraw(address _bonding) external override nonReentrant {
    if (pendingUnbonds[msg.sender][_bonding] == 0) revert UnbondsUnexistent();
    if (canWithdrawAfter[msg.sender][_bonding] >= block.timestamp) revert UnbondsLocked();
    if (disputes[msg.sender]) revert Disputed();

    uint256 _amount = pendingUnbonds[msg.sender][_bonding];

    if (_bonding == keep3rV1) {
      IKeep3rV1Proxy(keep3rV1Proxy).mint(_amount);
    }

    delete pendingUnbonds[msg.sender][_bonding];
    delete canWithdrawAfter[msg.sender][_bonding];

    IERC20(_bonding).safeTransfer(msg.sender, _amount);

    emit Withdrawal(msg.sender, _bonding, _amount);
  }

  function _activate(address _keeper, address _bonding) internal returns (uint256 _amount) {
    if (firstSeen[_keeper] == 0) {
      firstSeen[_keeper] = block.timestamp;
    }
    _keepers.add(_keeper);
    _amount = pendingBonds[_keeper][_bonding];
    delete pendingBonds[_keeper][_bonding];

    // bond provided tokens
    bonds[_keeper][_bonding] += _amount;
    if (_bonding == keep3rV1) {
      IKeep3rV1(keep3rV1).burn(_amount);
    }
  }
}

File 36 of 39 : IKeep3rV1.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';

// solhint-disable func-name-mixedcase
interface IKeep3rV1 is IERC20, IERC20Metadata {
  // Structs
  struct Checkpoint {
    uint32 fromBlock;
    uint256 votes;
  }

  // Events
  event DelegateChanged(address indexed _delegator, address indexed _fromDelegate, address indexed _toDelegate);
  event DelegateVotesChanged(address indexed _delegate, uint256 _previousBalance, uint256 _newBalance);
  event SubmitJob(address indexed _job, address indexed _liquidity, address indexed _provider, uint256 _block, uint256 _credit);
  event ApplyCredit(address indexed _job, address indexed _liquidity, address indexed _provider, uint256 _block, uint256 _credit);
  event RemoveJob(address indexed _job, address indexed _liquidity, address indexed _provider, uint256 _block, uint256 _credit);
  event UnbondJob(address indexed _job, address indexed _liquidity, address indexed _provider, uint256 _block, uint256 _credit);
  event JobAdded(address indexed _job, uint256 _block, address _governance);
  event JobRemoved(address indexed _job, uint256 _block, address _governance);
  event KeeperWorked(address indexed _credit, address indexed _job, address indexed _keeper, uint256 _block, uint256 _amount);
  event KeeperBonding(address indexed _keeper, uint256 _block, uint256 _active, uint256 _bond);
  event KeeperBonded(address indexed _keeper, uint256 _block, uint256 _activated, uint256 _bond);
  event KeeperUnbonding(address indexed _keeper, uint256 _block, uint256 _deactive, uint256 _bond);
  event KeeperUnbound(address indexed _keeper, uint256 _block, uint256 _deactivated, uint256 _bond);
  event KeeperSlashed(address indexed _keeper, address indexed _slasher, uint256 _block, uint256 _slash);
  event KeeperDispute(address indexed _keeper, uint256 _block);
  event KeeperResolved(address indexed _keeper, uint256 _block);
  event TokenCreditAddition(address indexed _credit, address indexed _job, address indexed _creditor, uint256 _block, uint256 _amount);

  // Variables
  function KPRH() external returns (address);

  function delegates(address _delegator) external view returns (address);

  function checkpoints(address _account, uint32 _checkpoint) external view returns (Checkpoint memory);

  function numCheckpoints(address _account) external view returns (uint32);

  function DOMAIN_TYPEHASH() external returns (bytes32);

  function DOMAINSEPARATOR() external returns (bytes32);

  function DELEGATION_TYPEHASH() external returns (bytes32);

  function PERMIT_TYPEHASH() external returns (bytes32);

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

  function BOND() external returns (uint256);

  function UNBOND() external returns (uint256);

  function LIQUIDITYBOND() external returns (uint256);

  function FEE() external returns (uint256);

  function BASE() external returns (uint256);

  function ETH() external returns (address);

  function bondings(address _user, address _bonding) external view returns (uint256);

  function canWithdrawAfter(address _user, address _bonding) external view returns (uint256);

  function pendingUnbonds(address _keeper, address _bonding) external view returns (uint256);

  function pendingbonds(address _keeper, address _bonding) external view returns (uint256);

  function bonds(address _keeper, address _bonding) external view returns (uint256);

  function votes(address _delegator) external view returns (uint256);

  function firstSeen(address _keeper) external view returns (uint256);

  function disputes(address _keeper) external view returns (bool);

  function lastJob(address _keeper) external view returns (uint256);

  function workCompleted(address _keeper) external view returns (uint256);

  function jobs(address _job) external view returns (bool);

  function credits(address _job, address _credit) external view returns (uint256);

  function liquidityProvided(
    address _provider,
    address _liquidity,
    address _job
  ) external view returns (uint256);

  function liquidityUnbonding(
    address _provider,
    address _liquidity,
    address _job
  ) external view returns (uint256);

  function liquidityAmountsUnbonding(
    address _provider,
    address _liquidity,
    address _job
  ) external view returns (uint256);

  function jobProposalDelay(address _job) external view returns (uint256);

  function liquidityApplied(
    address _provider,
    address _liquidity,
    address _job
  ) external view returns (uint256);

  function liquidityAmount(
    address _provider,
    address _liquidity,
    address _job
  ) external view returns (uint256);

  function keepers(address _keeper) external view returns (bool);

  function blacklist(address _keeper) external view returns (bool);

  function keeperList(uint256 _index) external view returns (address);

  function jobList(uint256 _index) external view returns (address);

  function governance() external returns (address);

  function pendingGovernance() external returns (address);

  function liquidityAccepted(address _liquidity) external view returns (bool);

  function liquidityPairs(uint256 _index) external view returns (address);

  // Methods
  function getCurrentVotes(address _account) external view returns (uint256);

  function addCreditETH(address _job) external payable;

  function addCredit(
    address _credit,
    address _job,
    uint256 _amount
  ) external;

  function addVotes(address _voter, uint256 _amount) external;

  function removeVotes(address _voter, uint256 _amount) external;

  function addKPRCredit(address _job, uint256 _amount) external;

  function approveLiquidity(address _liquidity) external;

  function revokeLiquidity(address _liquidity) external;

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

  function addLiquidityToJob(
    address _liquidity,
    address _job,
    uint256 _amount
  ) external;

  function applyCreditToJob(
    address _provider,
    address _liquidity,
    address _job
  ) external;

  function unbondLiquidityFromJob(
    address _liquidity,
    address _job,
    uint256 _amount
  ) external;

  function removeLiquidityFromJob(address _liquidity, address _job) external;

  function mint(uint256 _amount) external;

  function burn(uint256 _amount) external;

  function worked(address _keeper) external;

  function receipt(
    address _credit,
    address _keeper,
    uint256 _amount
  ) external;

  function receiptETH(address _keeper, uint256 _amount) external;

  function addJob(address _job) external;

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

  function removeJob(address _job) external;

  function setKeep3rHelper(address _keep3rHelper) external;

  function setGovernance(address _governance) external;

  function acceptGovernance() external;

  function isKeeper(address _keeper) external returns (bool);

  function isMinKeeper(
    address _keeper,
    uint256 _minBond,
    uint256 _earned,
    uint256 _age
  ) external returns (bool);

  function isBondedKeeper(
    address _keeper,
    address _bond,
    uint256 _minBond,
    uint256 _earned,
    uint256 _age
  ) external returns (bool);

  function bond(address _bonding, uint256 _amount) external;

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

  function activate(address _bonding) external;

  function unbond(address _bonding, uint256 _amount) external;

  function slash(
    address _bonded,
    address _keeper,
    uint256 _amount
  ) external;

  function withdraw(address _bonding) external;

  function dispute(address _keeper) external;

  function revoke(address _keeper) external;

  function resolve(address _keeper) external;

  function permit(
    address _owner,
    address _spender,
    uint256 _amount,
    uint256 _deadline,
    uint8 _v,
    bytes32 _r,
    bytes32 _s
  ) external;
}

File 37 of 39 : IKeep3rKeepers.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

/// @title Keep3rKeeperFundable contract
/// @notice Handles the actions required to become a keeper
interface IKeep3rKeeperFundable {
  // Events

  /// @notice Emitted when Keep3rKeeperFundable#activate is called
  /// @param _keeper The keeper that has been activated
  /// @param _bond The asset the keeper has bonded
  /// @param _amount The amount of the asset the keeper has bonded
  event Activation(address indexed _keeper, address indexed _bond, uint256 _amount);

  /// @notice Emitted when Keep3rKeeperFundable#withdraw is called
  /// @param _keeper The caller of Keep3rKeeperFundable#withdraw function
  /// @param _bond The asset to withdraw from the bonding pool
  /// @param _amount The amount of funds withdrawn
  event Withdrawal(address indexed _keeper, address indexed _bond, uint256 _amount);

  // Errors

  /// @notice Throws when the address that is trying to register as a job is already a job
  error AlreadyAJob();

  // Methods

  /// @notice Beginning of the bonding process
  /// @param _bonding The asset being bonded
  /// @param _amount The amount of bonding asset being bonded
  function bond(address _bonding, uint256 _amount) external;

  /// @notice Beginning of the unbonding process
  /// @param _bonding The asset being unbonded
  /// @param _amount Allows for partial unbonding
  function unbond(address _bonding, uint256 _amount) external;

  /// @notice End of the bonding process after bonding time has passed
  /// @param _bonding The asset being activated as bond collateral
  function activate(address _bonding) external;

  /// @notice Withdraw funds after unbonding has finished
  /// @param _bonding The asset to withdraw from the bonding pool
  function withdraw(address _bonding) external;
}

/// @title Keep3rKeeperDisputable contract
/// @notice Handles the actions that can be taken on a disputed keeper
interface IKeep3rKeeperDisputable {
  // Events

  /// @notice Emitted when Keep3rKeeperDisputable#slash is called
  /// @param _keeper The address of the slashed keeper
  /// @param _slasher The user that called Keep3rKeeperDisputable#slash
  /// @param _amount The amount of credits slashed from the keeper
  event KeeperSlash(address indexed _keeper, address indexed _slasher, uint256 _amount);

  /// @notice Emitted when Keep3rKeeperDisputable#revoke is called
  /// @param _keeper The address of the revoked keeper
  /// @param _slasher The user that called Keep3rKeeperDisputable#revoke
  event KeeperRevoke(address indexed _keeper, address indexed _slasher);

  // Methods

  /// @notice Allows governance to slash a keeper based on a dispute
  /// @param _keeper The address being slashed
  /// @param _bonded The asset being slashed
  /// @param _bondAmount The bonded amount being slashed
  /// @param _unbondAmount The pending unbond amount being slashed
  function slash(
    address _keeper,
    address _bonded,
    uint256 _bondAmount,
    uint256 _unbondAmount
  ) external;

  /// @notice Blacklists a keeper from participating in the network
  /// @param _keeper The address being slashed
  function revoke(address _keeper) external;
}

// solhint-disable-next-line no-empty-blocks

/// @title Keep3rKeepers contract
interface IKeep3rKeepers is IKeep3rKeeperDisputable {

}

File 38 of 39 : IKeep3rV1Proxy.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;

import '../peripherals/IGovernable.sol';

interface IKeep3rV1Proxy is IGovernable {
  // Structs
  struct Recipient {
    address recipient;
    uint256 caps;
  }

  // Variables
  function keep3rV1() external view returns (address);

  function minter() external view returns (address);

  function next(address) external view returns (uint256);

  function caps(address) external view returns (uint256);

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

  function recipientsCaps() external view returns (Recipient[] memory);

  // Errors
  error Cooldown();
  error NoDrawableAmount();
  error ZeroAddress();
  error OnlyMinter();

  // Methods
  function addRecipient(address recipient, uint256 amount) external;

  function removeRecipient(address recipient) external;

  function draw() external returns (uint256 _amount);

  function setKeep3rV1(address _keep3rV1) external;

  function setMinter(address _minter) external;

  function mint(uint256 _amount) external;

  function mint(address _account, uint256 _amount) external;

  function setKeep3rV1Governance(address _governance) external;

  function acceptKeep3rV1Governance() external;

  function dispute(address _keeper) external;

  function slash(
    address _bonded,
    address _keeper,
    uint256 _amount
  ) external;

  function revoke(address _keeper) external;

  function resolve(address _keeper) external;

  function addJob(address _job) external;

  function removeJob(address _job) external;

  function addKPRCredit(address _job, uint256 _amount) external;

  function approveLiquidity(address _liquidity) external;

  function revokeLiquidity(address _liquidity) external;

  function setKeep3rHelper(address _keep3rHelper) external;

  function addVotes(address _voter, uint256 _amount) external;

  function removeVotes(address _voter, uint256 _amount) external;
}

File 39 of 39 : IDustCollector.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.4 <0.9.0;

import './IBaseErrors.sol';

interface IDustCollector is IBaseErrors {
  /// @notice Emitted when dust is sent
  /// @param _token The token that will be transferred
  /// @param _amount The amount of the token that will be transferred
  /// @param _to The address which will receive the funds
  event DustSent(address _token, uint256 _amount, address _to);

  /// @notice Allows an authorized user to transfer the tokens or eth that may have been left in a contract
  /// @param _token The token that will be transferred
  /// @param _amount The amount of the token that will be transferred
  /// @param _to The address that will receive the idle funds
  function sendDust(
    address _token,
    uint256 _amount,
    address _to
  ) external;
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_governance","type":"address"},{"internalType":"address","name":"_keep3rHelper","type":"address"},{"internalType":"address","name":"_keep3rV1","type":"address"},{"internalType":"address","name":"_keep3rV1Proxy","type":"address"},{"internalType":"address","name":"_kp3rWethPool","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyAJob","type":"error"},{"inputs":[],"name":"AlreadyAKeeper","type":"error"},{"inputs":[],"name":"AlreadyDisputed","type":"error"},{"inputs":[],"name":"BondsLocked","type":"error"},{"inputs":[],"name":"BondsUnexistent","type":"error"},{"inputs":[],"name":"Disputed","type":"error"},{"inputs":[],"name":"DisputerExistent","type":"error"},{"inputs":[],"name":"DisputerUnexistent","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InsufficientJobTokenCredits","type":"error"},{"inputs":[],"name":"JobAlreadyAdded","type":"error"},{"inputs":[],"name":"JobDisputed","type":"error"},{"inputs":[],"name":"JobLiquidityInsufficient","type":"error"},{"inputs":[],"name":"JobLiquidityLessThanMin","type":"error"},{"inputs":[],"name":"JobLiquidityUnexistent","type":"error"},{"inputs":[],"name":"JobMigrationImpossible","type":"error"},{"inputs":[],"name":"JobMigrationLocked","type":"error"},{"inputs":[],"name":"JobMigrationUnavailable","type":"error"},{"inputs":[],"name":"JobTokenCreditsLocked","type":"error"},{"inputs":[],"name":"JobTokenInsufficient","type":"error"},{"inputs":[],"name":"JobTokenUnexistent","type":"error"},{"inputs":[],"name":"JobUnapproved","type":"error"},{"inputs":[],"name":"JobUnavailable","type":"error"},{"inputs":[],"name":"LiquidityPairApproved","type":"error"},{"inputs":[],"name":"LiquidityPairUnapproved","type":"error"},{"inputs":[],"name":"LiquidityPairUnexistent","type":"error"},{"inputs":[],"name":"MinRewardPeriod","type":"error"},{"inputs":[],"name":"NoGovernanceZeroAddress","type":"error"},{"inputs":[],"name":"NotDisputed","type":"error"},{"inputs":[],"name":"OnlyDisputer","type":"error"},{"inputs":[],"name":"OnlyGovernance","type":"error"},{"inputs":[],"name":"OnlyJobOwner","type":"error"},{"inputs":[],"name":"OnlyPendingGovernance","type":"error"},{"inputs":[],"name":"OnlyPendingJobOwner","type":"error"},{"inputs":[],"name":"OnlySlasher","type":"error"},{"inputs":[],"name":"SlasherExistent","type":"error"},{"inputs":[],"name":"SlasherUnexistent","type":"error"},{"inputs":[],"name":"TokenUnallowed","type":"error"},{"inputs":[],"name":"UnbondsLocked","type":"error"},{"inputs":[],"name":"UnbondsUnexistent","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_keeper","type":"address"},{"indexed":true,"internalType":"address","name":"_bond","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Activation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_bondTime","type":"uint256"}],"name":"BondTimeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_keeper","type":"address"},{"indexed":true,"internalType":"address","name":"_bonding","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Bonding","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_jobOrKeeper","type":"address"},{"indexed":true,"internalType":"address","name":"_disputer","type":"address"}],"name":"Dispute","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_disputer","type":"address"}],"name":"DisputerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_disputer","type":"address"}],"name":"DisputerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_to","type":"address"}],"name":"DustSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"FeeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_pendingGovernance","type":"address"}],"name":"GovernanceProposal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_governance","type":"address"}],"name":"GovernanceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_inflationPeriod","type":"uint256"}],"name":"InflationPeriodChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":true,"internalType":"address","name":"_jobOwner","type":"address"}],"name":"JobAddition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_fromJob","type":"address"},{"indexed":false,"internalType":"address","name":"_toJob","type":"address"}],"name":"JobMigrationRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_fromJob","type":"address"},{"indexed":true,"internalType":"address","name":"_toJob","type":"address"}],"name":"JobMigrationSuccessful","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"JobOwnershipAssent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_pendingOwner","type":"address"}],"name":"JobOwnershipChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":false,"internalType":"address","name":"_liquidity","type":"address"},{"indexed":true,"internalType":"address","name":"_slasher","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"JobSlashLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_slasher","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"JobSlashToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_keep3rHelper","type":"address"}],"name":"Keep3rHelperChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_keep3rV1","type":"address"}],"name":"Keep3rV1Change","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_keep3rV1Proxy","type":"address"}],"name":"Keep3rV1ProxyChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_keeper","type":"address"},{"indexed":true,"internalType":"address","name":"_slasher","type":"address"}],"name":"KeeperRevoke","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_keeper","type":"address"},{"indexed":true,"internalType":"address","name":"_slasher","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"KeeperSlash","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_gasLeft","type":"uint256"}],"name":"KeeperValidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_credit","type":"address"},{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":true,"internalType":"address","name":"_keeper","type":"address"},{"indexed":false,"internalType":"uint256","name":"_payment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_gasLeft","type":"uint256"}],"name":"KeeperWork","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_kp3rWethPool","type":"address"}],"name":"Kp3rWethPoolChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":true,"internalType":"address","name":"_liquidity","type":"address"},{"indexed":true,"internalType":"address","name":"_provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"LiquidityAddition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_liquidity","type":"address"}],"name":"LiquidityApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":false,"internalType":"uint256","name":"_rewardedAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_currentCredits","type":"uint256"}],"name":"LiquidityCreditsForced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":false,"internalType":"uint256","name":"_rewardedAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_currentCredits","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_periodCredits","type":"uint256"}],"name":"LiquidityCreditsReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_liquidityMinimum","type":"uint256"}],"name":"LiquidityMinimumChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_liquidity","type":"address"}],"name":"LiquidityRevocation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":true,"internalType":"address","name":"_liquidity","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"LiquidityWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_jobOrKeeper","type":"address"},{"indexed":true,"internalType":"address","name":"_resolver","type":"address"}],"name":"Resolve","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_rewardPeriodTime","type":"uint256"}],"name":"RewardPeriodTimeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_slasher","type":"address"}],"name":"SlasherAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_slasher","type":"address"}],"name":"SlasherRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"TokenCreditAddition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_job","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"TokenCreditWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_unbondTime","type":"uint256"}],"name":"UnbondTimeChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_keeperOrJob","type":"address"},{"indexed":true,"internalType":"address","name":"_unbonding","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Unbonding","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_keeper","type":"address"},{"indexed":true,"internalType":"address","name":"_bond","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"acceptGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_fromJob","type":"address"},{"internalType":"address","name":"_toJob","type":"address"}],"name":"acceptJobMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"}],"name":"acceptJobOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bonding","type":"address"}],"name":"activate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_disputer","type":"address"}],"name":"addDisputer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"}],"name":"addJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"},{"internalType":"address","name":"_liquidity","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addLiquidityToJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_slasher","type":"address"}],"name":"addSlasher","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addTokenCreditsToJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidity","type":"address"}],"name":"approveLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"approvedLiquidities","outputs":[{"internalType":"address[]","name":"_list","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bonding","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"bond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bondTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"uint256","name":"_payment","type":"uint256"}],"name":"bondedPayment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"bonds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"canActivateAfter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"canWithdrawAfter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"},{"internalType":"address","name":"_newOwner","type":"address"}],"name":"changeJobOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"directTokenPayment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_jobOrKeeper","type":"address"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"disputers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"disputes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"firstSeen","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"forceLiquidityCreditsToJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hasBonded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"inflationPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_bond","type":"address"},{"internalType":"uint256","name":"_minBond","type":"uint256"},{"internalType":"uint256","name":"_earned","type":"uint256"},{"internalType":"uint256","name":"_age","type":"uint256"}],"name":"isBondedKeeper","outputs":[{"internalType":"bool","name":"_isBondedKeeper","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"isKeeper","outputs":[{"internalType":"bool","name":"_isKeeper","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"}],"name":"jobLiquidityCredits","outputs":[{"internalType":"uint256","name":"_liquidityCredits","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"jobOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"jobPendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"}],"name":"jobPeriodCredits","outputs":[{"internalType":"uint256","name":"_periodCredits","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"jobTokenCredits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"jobTokenCreditsAddedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"jobs","outputs":[{"internalType":"address[]","name":"_list","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keep3rHelper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keep3rV1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keep3rV1Proxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keepers","outputs":[{"internalType":"address[]","name":"_list","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kp3rWethPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"liquidityAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityMinimum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_fromJob","type":"address"},{"internalType":"address","name":"_toJob","type":"address"}],"name":"migrateJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidity","type":"address"}],"name":"observeLiquidity","outputs":[{"components":[{"internalType":"int56","name":"current","type":"int56"},{"internalType":"int56","name":"difference","type":"int56"},{"internalType":"uint256","name":"period","type":"uint256"}],"internalType":"struct IKeep3rJobFundableLiquidity.TickCache","name":"_tickCache","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"pendingBonds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingGovernance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pendingJobMigrations","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"pendingUnbonds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidity","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"quoteLiquidity","outputs":[{"internalType":"uint256","name":"_periodCredits","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_disputer","type":"address"}],"name":"removeDisputer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_slasher","type":"address"}],"name":"removeSlasher","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_jobOrKeeper","type":"address"}],"name":"resolve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"revoke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_liquidity","type":"address"}],"name":"revokeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPeriodTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"sendDust","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bondTime","type":"uint256"}],"name":"setBondTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_governance","type":"address"}],"name":"setGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_inflationPeriod","type":"uint256"}],"name":"setInflationPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keep3rHelper","type":"address"}],"name":"setKeep3rHelper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keep3rV1","type":"address"}],"name":"setKeep3rV1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keep3rV1Proxy","type":"address"}],"name":"setKeep3rV1Proxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_kp3rWethPool","type":"address"}],"name":"setKp3rWethPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_liquidityMinimum","type":"uint256"}],"name":"setLiquidityMinimum","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardPeriodTime","type":"uint256"}],"name":"setRewardPeriodTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unbondTime","type":"uint256"}],"name":"setUnbondTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_bonded","type":"address"},{"internalType":"uint256","name":"_bondAmount","type":"uint256"},{"internalType":"uint256","name":"_unbondAmount","type":"uint256"}],"name":"slash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"},{"internalType":"address","name":"_liquidity","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"slashLiquidityFromJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"slashTokenFromJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"slashers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"}],"name":"totalJobCredits","outputs":[{"internalType":"uint256","name":"_credits","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bonding","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unbond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"},{"internalType":"address","name":"_liquidity","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unbondLiquidityFromJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unbondTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bonding","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"},{"internalType":"address","name":"_liquidity","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"withdrawLiquidityFromJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_job","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"withdrawTokenCreditsFromJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"workCompleted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"worked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"workedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040526203f480601f55621275006020556729a2241af62c000060215562069780602255622cd300602355601e6024553480156200003e57600080fd5b5060405162006244380380620062448339810160408190526200006191620001ce565b60016000558383838388806001600160a01b038116620000935760405162b293ed60e81b815260040160405180910390fd5b601780546001600160a01b03199081166001600160a01b0393841617909155601d80548216888416178155601b80548316888516179055601c80548316878516179055601e8054831686851690811782556000818152600e602052604090819020805490951690911790935590549054915163696a437b60e01b81529183166004830152909116915063696a437b9060240160206040518083038186803b1580156200013e57600080fd5b505afa15801562000153573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200017991906200023e565b6001600160a01b03919091166000908152600f60205260409020805460ff191691151591909117905550620002699650505050505050565b80516001600160a01b0381168114620001c957600080fd5b919050565b600080600080600060a08688031215620001e757600080fd5b620001f286620001b1565b94506200020260208701620001b1565b93506200021260408701620001b1565b92506200022260608701620001b1565b91506200023260808701620001b1565b90509295509295909350565b6000602082840312156200025157600080fd5b815180151581146200026257600080fd5b9392505050565b615fcb80620002796000396000f3fe608060405234801561001057600080fd5b50600436106103ec5760003560e01c806390a4684e1161020d578063c5198abc11610121578063c5198abc146109e1578063c7ae40d0146109f4578063cb4be2bb14610a07578063cb54694d14610a1a578063cd22af1b14610a2d578063d55995fe14610a58578063dd2080d614610a6b578063ddca3f4314610a7e578063e326ac4314610a87578063ebbb619414610aa7578063ec00cdfc14610aba578063ec8ca64314610acd578063f0f346b914610af6578063f11a1d1a14610b09578063f136a09d14610b1c578063f25e311b14610b3c578063f39c38a014610b4f578063f75f9f7b14610b62578063f9d46cf214610b75578063fc253d2b14610b88578063fe75bc4614610b9157600080fd5b806390a4684e146107f4578063951dc22c14610807578063966abd001461080f57806398e90a0f146108225780639d5c33d81461084b578063a21458091461085e578063a39744b514610871578063a515366a1461089c578063a5d059ca146108af578063a676f9ff146108c2578063a7d2e784146108e2578063aac6aa9c146108eb578063ab033ea9146108fe578063af320e8114610911578063b0103b1a14610924578063b239223314610947578063b440027f1461095a578063b600702a14610985578063b7e7734014610998578063b87fcbff146109ab578063c20297f0146109ce57600080fd5b806359a2255e1161030457806359a2255e146106505780635aa6e675146106635780635ebe23f0146106765780635feeb7941461067f578063633fb68f1461069257806364bb43ee1461069b57806368a9f19c146106ae578063694798e6146106c157806369fe0e2d146106ec5780636ba42aaa146106ff5780636cf262bc146107125780636e2a9ca61461072557806372da828a1461073857806374a8f1031461074b578063768b5d901461075e5780637b40c913146107675780637c8fce231461077a578063878c723e146107825780638bb6dfa8146107ab5780638cb22b76146107be5780638fe204dd146107e157600080fd5b8063034d4c61146103f157806307b435c2146104175780630c620bce146104425780630d6a1f87146104575780631101eb411461046a57806311466d721461047f57806315006b8214610492578063160e1e31146104bd578063165e62e7146104d0578063168f92e71461050d5780631b44555e146105385780631c5a9d9c146105585780631ef94b911461056b57806321040b011461058b578063238efcbc146105b6578063274a8db4146105be57806351cff8d9146105f157806352a4de291461060457806355ea6c4714610617578063575288bf1461062a578063594a3a931461063d575b600080fd5b6104046103ff36600461591c565b610ba4565b6040519081526020015b60405180910390f35b610404610425366004615956565b601260209081526000928352604080842090915290825290205481565b61044a610caa565b60405161040e9190615ccb565b610404610465366004615b05565b610cbb565b61047d6104783660046159da565b610dc1565b005b61047d61048d366004615b05565b610f1b565b6104046104a0366004615956565b601060209081526000928352604080842090915290825290205481565b61047d6104cb36600461591c565b6110aa565b6104e36104de36600461591c565b611210565b604080518251600690810b825260208085015190910b90820152918101519082015260600161040e565b61040461051b366004615956565b600960209081526000928352604080842090915290825290205481565b61040461054636600461591c565b60056020526000908152604090205481565b61047d61056636600461591c565b6115d6565b601b5461057e906001600160a01b031681565b60405161040e9190615c42565b610404610599366004615956565b601360209081526000928352604080842090915290825290205481565b61047d61170f565b6105e16105cc36600461591c565b601a6020526000908152604090205460ff1681565b604051901515815260200161040e565b61047d6105ff36600461591c565b61179b565b61047d6106123660046159da565b6119a4565b61047d61062536600461591c565b611bd5565b61047d6106383660046159da565b611c89565b61047d61064b366004615956565b611f4c565b61047d61065e36600461591c565b611ff1565b60175461057e906001600160a01b031681565b610404601f5481565b61047d61068d36600461591c565b6120a3565b61040460215481565b61047d6106a936600461591c565b61230d565b61047d6106bc36600461591c565b61238f565b6104046106cf366004615956565b602860209081526000928352604080842090915290825290205481565b61047d6106fa366004615bc6565b612447565b6105e161070d36600461591c565b6124a7565b61040461072036600461591c565b612507565b61047d6107333660046159da565b61263d565b61047d61074636600461591c565b61278c565b61047d61075936600461591c565b612829565b61040460225481565b601e5461057e906001600160a01b031681565b61044a612924565b61057e61079036600461591c565b6001602052600090815260409020546001600160a01b031681565b6104046107b936600461591c565b612930565b6105e16107cc36600461591c565b60146020526000908152604090205460ff1681565b61047d6107ef366004615bc6565b6129d3565b61047d610802366004615956565b612a31565b61044a612b1f565b61047d61081d366004615b31565b612b2b565b61057e61083036600461591c565b6002602052600090815260409020546001600160a01b031681565b61047d61085936600461591c565b612c41565b61047d61086c36600461598f565b612cf9565b61040461087f366004615956565b600860209081526000928352604080842090915290825290205481565b61047d6108aa366004615b05565b612ec9565b61047d6108bd366004615b05565b61312a565b6104046108d036600461591c565b60296020526000908152604090205481565b61040460205481565b61047d6108f936600461591c565b6131fd565b61047d61090c36600461591c565b6132b1565b61047d61091f366004615956565b613327565b6105e161093236600461591c565b60076020526000908152604090205460ff1681565b61047d610955366004615bc6565b6137a6565b610404610968366004615956565b602560209081526000928352604080842090915290825290205481565b61047d61099336600461591c565b613806565b61047d6109a6366004615bc6565b613a2b565b6105e16109b936600461591c565b60196020526000908152604090205460ff1681565b61047d6109dc366004615a6e565b613a8b565b61047d6109ef36600461591c565b613b4d565b601c5461057e906001600160a01b031681565b61047d610a1536600461591c565b613c12565b61047d610a28366004615bc6565b613caf565b610404610a3b366004615956565b601160209081526000928352604080842090915290825290205481565b61047d610a66366004615a1b565b613d33565b61047d610a793660046159da565b613f6a565b61040460245481565b610404610a9536600461591c565b60066020526000908152604090205481565b61047d610ab5366004615bc6565b6140e7565b61047d610ac836600461591c565b614147565b61057e610adb36600461591c565b602c602052600090815260409020546001600160a01b031681565b61047d610b0436600461591c565b6141e4565b601d5461057e906001600160a01b031681565b610404610b2a36600461591c565b602a6020526000908152604090205481565b61047d610b4a3660046159da565b614298565b60185461057e906001600160a01b031681565b61047d610b7036600461591c565b6144dd565b6105e1610b83366004615ab4565b614595565b61040460235481565b61047d610b9f366004615b05565b61467e565b600080610bb083612507565b6022549091504290610bcb90610bc69083615e4c565b61476e565b6001600160a01b0385166000908152602960205260409020541115610c6f576022546001600160a01b038516600090815260296020526040902054610c109042615e4c565b10610c4c576022546001600160a01b038516600090815260296020526040902054610c3b9190615db1565b610c459082615e4c565b9050610c85565b6001600160a01b038416600090815260296020526040902054610c459082615e4c565b610c784261476e565b610c829082615e4c565b90505b610c8f8183614788565b610c9885612930565b610ca29190615db1565b949350505050565b6060610cb660266147b2565b905090565b6000610cc86026846147c6565b15610dbb576000610cd884611210565b90508060400151600014610db9576001600160a01b0384166000908152600f602052604081205460ff16610d19578160200151610d1490615ebe565b610d1f565b81602001515b601d5460225460405163a0d2710760e01b8152929350610db0926001600160a01b039092169163a0d2710791610d5b9189918791600401615d82565b60206040518083038186803b158015610d7357600080fd5b505afa158015610d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dab9190615bdf565b6147e8565b92505050610dbb565b505b92915050565b6001600160a01b038381166000908152600160205260409020548491163314610dfd57604051636efb4f4160e11b815260040160405180910390fd5b602054610e0a9042615db1565b6001600160a01b03808616600081815260126020908152604080832094891680845294825280832095909555918152601382528381209281529190529081208054849290610e59908490615db1565b90915550610e6a90508484846147f9565b6001600160a01b038085166000908152602860209081526040808320938716835292905220548015801590610ea95750602154610ea78286614a07565b105b15610ec757604051636f447fcd60e11b815260040160405180910390fd5b836001600160a01b0316856001600160a01b03167f9aaab310d247ad45aef26bbdefc4ebf20c728fdb84c92b95b2b05d21826940de85604051610f0c91815260200190565b60405180910390a35050505050565b3360008181526007602052604090205460ff1615610f4c5760405163ad2fdf3b60e01b815260040160405180910390fd5b610f576015826147c6565b610f735760405162941a5760e11b815260040160405180910390fd5b610f7c81614b25565b15610fd7576001600160a01b038116600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f7683398151915293610fce9390929091615d9b565b60405180910390a25b6001600160a01b0381166000908152600a60205260409020548211156110565761100081614cfb565b6001600160a01b038116600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f768339815191529361104d9390929091615d9b565b60405180910390a25b611061818484614d89565b601b546001600160a01b03808516918382169116600080516020615f568339815191528561108d614e6d565b6040805192835260208301919091520160405180910390a4505050565b6017546001600160a01b031633146110d5576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166110fc5760405163d92e233d60e01b815260040160405180910390fd5b601e80546001600160a01b038084166001600160a01b031992831681179093556000838152600e6020526040908190208054909316909317909155601d54915163696a437b60e01b815291169063696a437b9061115d908490600401615c42565b60206040518083038186803b15801561117557600080fd5b505afa158015611189573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ad9190615b68565b6001600160a01b0382166000908152600f602052604090819020805460ff191692151592909217909155517f9bb1515b0fc2645a3f011162460a22fdd512e0bca265e7dc9ba6bceae8930afa90611205908390615c42565b60405180910390a150565b60408051606081018252600080825260208201819052918101919091526112364261476e565b6001600160a01b0383166000908152602b602052604090206001015414156112ac57506001600160a01b03166000908152602b602090815260409182902082516060810184528154600681810b810b810b8352600160381b909104810b810b900b92810192909252600101549181019190915290565b6000806112c060225442610bc69190615e4c565b6001600160a01b0385166000908152602b602052604090206001015490915081141561142457604080516001808252818301909252600091602080830190803683375050506001600160a01b0386166000908152602b602052604090205490915060060b61132d4261476e565b6113379042615e4c565b8260008151811061134a5761134a615f27565b63ffffffff909216602092830291909101820152601d546001600160a01b038881166000908152600e90935260409283902054925163dc686d9160e01b81529181169263dc686d91926113a69291909116908690600401615c56565b60606040518083038186803b1580156113be57600080fd5b505afa1580156113d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f69190615b83565b600692830b90920b80885291955061141091839150615dfc565b600690810b900b6020860152506115ad9050565b6001600160a01b0384166000908152602b60205260409020600101548111156115ad576040805160028082526060820183526000926020830190803683370190505090506114714261476e565b61147b9042615e4c565b8160008151811061148e5761148e615f27565b602002602001019063ffffffff16908163ffffffff16815250506022546114b44261476e565b6114be9042615e4c565b6114c89190615db1565b816001815181106114db576114db615f27565b63ffffffff909216602092830291909101820152601d546001600160a01b038781166000908152600e909352604080842054905163dc686d9160e01b81529282169263dc686d91926115339216908690600401615c56565b60606040518083038186803b15801561154b57600080fd5b505afa15801561155f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115839190615b83565b600692830b90920b808852919550915061159e908290615dfc565b600690810b900b602086015250505b81156115c6576115bc4261476e565b60408401526115ce565b600060408401525b50505b919050565b3360009081526007602052604090205460ff1615611607576040516362e6201d60e01b815260040160405180910390fd5b3360009081526011602090815260408083206001600160a01b038516845290915290205461164857604051636258f48160e01b815260040160405180910390fd5b3360009081526011602090815260408083206001600160a01b0385168452909152902054421161168b57604051630fd0eeef60e11b815260040160405180910390fd5b3360008181526011602090815260408083206001600160a01b03861684529091528120819055906116bc9083614e87565b9050816001600160a01b0316336001600160a01b03167f3673530133b6da67e9854f605b0cfa7bb9798cd33c18036dfc10d8da7c4d4a758360405161170391815260200190565b60405180910390a35050565b6018546001600160a01b0316331461173a57604051637ef5703160e11b815260040160405180910390fd5b60188054601780546001600160a01b0383166001600160a01b031991821681179092559091169091556040517fc73be659241aade67e9a059bcf21494955018b213dbd1179054ccf928b13f3b69161179191615c42565b60405180910390a1565b600260005414156117c75760405162461bcd60e51b81526004016117be90615d4b565b60405180910390fd5b600260009081553381526013602090815260408083206001600160a01b038516845290915290205461180c5760405163184c088160e21b815260040160405180910390fd5b3360009081526012602090815260408083206001600160a01b0385168452909152902054421161184f576040516327cfdcb760e01b815260040160405180910390fd5b3360009081526007602052604090205460ff1615611880576040516362e6201d60e01b815260040160405180910390fd5b3360009081526013602090815260408083206001600160a01b0385811680865291909352922054601b5490929116141561191357601c5460405163140e25ad60e31b8152600481018390526001600160a01b039091169063a0712d6890602401600060405180830381600087803b1580156118fa57600080fd5b505af115801561190e573d6000803e3d6000fd5b505050505b3360008181526013602090815260408083206001600160a01b0387168085529083528184208490558484526012835281842081855290925282209190915561195b9183614f9e565b6040518181526001600160a01b0383169033907f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b63989060200160405180910390a350506001600055565b600260005414156119c75760405162461bcd60e51b81526004016117be90615d4b565b60026000556119d76026836147c6565b6119f45760405163e0b6aead60e01b815260040160405180910390fd5b6119ff6015846147c6565b611a1c57604051636211d34960e01b815260040160405180910390fd5b6001600160a01b0383166000908152600d60205260409020611a3e9083614ff9565b50611a488361500e565b6021546001600160a01b03808516600090815260286020908152604080832093871683529290522054611a8690611a80908490615db1565b84614a07565b1015611aa557604051636f447fcd60e11b815260040160405180910390fd5b6001600160a01b038316600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f7683398151915293611af29390929091615d9b565b60405180910390a2611b0f6001600160a01b03831633308461506c565b6001600160a01b03808416600090815260286020908152604080832093861683529290529081208054839290611b46908490615db1565b90915550611b599050610dab8284614a07565b6001600160a01b0384166000908152600b602052604081208054909190611b81908490615db1565b909155505060405181815233906001600160a01b0384811691908616907f4e186bc75a2220191b826baff3ee63c3e970e94e58a9007ff94c9a7b8e6ebb3f9060200160405180910390a45050600160005550565b336000908152601a602052604090205460ff16611c0557604051630942721960e31b815260040160405180910390fd5b6001600160a01b03811660009081526007602052604090205460ff16611c3e576040516310cec38560e21b815260040160405180910390fd5b6001600160a01b038116600081815260076020526040808220805460ff19169055513392917fe02b2375d8fb4aef3e5bc5d53bffcf70b6f185c5c93e69dcbe8b6cfc58e837e291a350565b60026000541415611cac5760405162461bcd60e51b81526004016117be90615d4b565b6002600055611cbc6015846147c6565b611cd957604051636211d34960e01b815260040160405180910390fd5b601b546001600160a01b0383811691161415611d075760405162822d9760e71b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190611d36903090600401615c42565b60206040518083038186803b158015611d4e57600080fd5b505afa158015611d62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d869190615bdf565b9050611d9d6001600160a01b03841633308561506c565b600081846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611dcc9190615c42565b60206040518083038186803b158015611de457600080fd5b505afa158015611df8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1c9190615bdf565b611e269190615e4c565b9050600061271060245483611e3b9190615ddd565b611e459190615dc9565b9050611e518183615e4c565b6001600160a01b038088166000908152600960209081526040808320938a1683529290529081208054909190611e88908490615db1565b90915550506001600160a01b0380871660009081526025602090815260408083208985168085529252909120429055601754611ec5921683614f9e565b6001600160a01b0386166000908152600c60205260409020611ee79086614ff9565b50336001600160a01b0316856001600160a01b0316876001600160a01b03167fec1a37d4a331a5059081e0fb5da1735e7890900cd215a4fb1e9f2779fd7b83eb85604051611f3791815260200190565b60405180910390a45050600160005550505050565b6001600160a01b038281166000908152600160205260409020548391163314611f8857604051636efb4f4160e11b815260040160405180910390fd5b6001600160a01b03838116600081815260026020908152604080832080546001600160a01b031916888716908117909155600190925280832054905191941692917fa8bad3f0b781e1d954af9945167d5f80bfe5e57930f17c93843187c77557a6b891a4505050565b6001600160a01b03818116600090815260026020526040902054829116331461202d5760405163cfe9663360e01b815260040160405180910390fd5b6001600160a01b03828116600081815260016020908152604080832080546002909352818420805487166001600160a01b031980861691909117909255805490911690555193169283929133917fcf30c54296d5eee76168b564c59c50578d49c271733a470f32707c8cfbc88a8b9190a4505050565b3360008181526007602052604090205460ff16156120d45760405163ad2fdf3b60e01b815260040160405180910390fd5b6120df6015826147c6565b6120fb5760405162941a5760e11b815260040160405180910390fd5b61210481614b25565b1561215f576001600160a01b038116600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f76833981519152936121569390929091615d9b565b60405180910390a25b601d546001600160a01b038381166000908152600860209081526040808320601b548516845290915280822054905163435b21c160e01b8152600481019190915290928392839291169063435b21c19060240160606040518083038186803b1580156121ca57600080fd5b505afa1580156121de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122029190615bf8565b9250925092506000612212614e6d565b90506000612222828486886150aa565b6001600160a01b0387166000908152600a60205260409020549091508111156122bc5761224e86614cfb565b6001600160a01b038616600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f768339815191529361229b9390929091615d9b565b60405180910390a26122ab614e6d565b91506122b9828486886150aa565b90505b6122c7868883614d89565b601b5460408051838152602081018590526001600160a01b038a8116938a821693911691600080516020615f56833981519152910160405180910390a450505050505050565b6017546001600160a01b03163314612338576040516354348f0360e01b815260040160405180910390fd5b612343602682615107565b61236057604051630a8d08b160e01b815260040160405180910390fd5b7f51199d699bdfd516fa88dd0d2f8487c40c147b4867acaa23adc8d4df6b098e56816040516112059190615c42565b6017546001600160a01b031633146123ba576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b03811660009081526019602052604090205460ff16156123f45760405163546da66560e11b815260040160405180910390fd5b6001600160a01b03811660009081526019602052604090819020805460ff19166001179055517f049ccb28ab796d3225573a065712f6e7754487ced56056cda8889c337511807b90611205908390615c42565b6017546001600160a01b03163314612472576040516354348f0360e01b815260040160405180910390fd5b60248190556040518181527f4c10ca068ff7002cf5da78f2f697d1e91f6f0ac27f7344b28e8ef25263f87e5d90602001611205565b60006124b1614e6d565b602e556124bf6003836147c6565b156115d1577f4851cad52e624c8f7a1d44c28a80db05988ba2451fc0db6b0ec338d8eca95afb602e546040516124f791815260200190565b60405180910390a1506001919050565b6000805b6001600160a01b0383166000908152600d6020526040902061252c9061511c565b811015612637576001600160a01b0383166000908152600d602052604081206125559083615126565b90506125626026826147c6565b1561262457600061257282611210565b90508060400151600014612622576001600160a01b0382166000908152600f602052604081205460ff166125b35781602001516125ae90615ebe565b6125b9565b81602001515b601d546001600160a01b03888116600090815260286020908152604080832089851684529091529081902054602254915163a0d2710760e01b815294955061261494929093169263a0d2710792610d5b928791600401615d82565b61261e9086615db1565b9450505b505b508061262f81615e8f565b91505061250b565b50919050565b3360009081526019602052604090205460ff1661266d57604051637e57b1e160e01b815260040160405180910390fd5b6001600160a01b03831660009081526007602052604090205460ff166126a6576040516310cec38560e21b815260040160405180910390fd5b6126b18383836147f9565b60175460405163a9059cbb60e01b81526001600160a01b038481169263a9059cbb926126e592909116908590600401615cb2565b602060405180830381600087803b1580156126ff57600080fd5b505af192505050801561272f575060408051601f3d908101601f1916820190925261272c91810190615b68565b60015b6127385761273a565b505b336001600160a01b0316836001600160a01b03167f6e10247c3c094d220ee99436c164b7f38d63b335a20ed817cbefaee4bb02d20e848460405161277f929190615cb2565b60405180910390a3505050565b6017546001600160a01b031633146127b7576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166127de5760405163d92e233d60e01b815260040160405180910390fd5b601d80546001600160a01b0319166001600160a01b0383161790556040517f71973fd672e51deb8f739b1f7e1eab991936645acd6f83e2bde6eeeaff5490b090611205908390615c42565b3360009081526019602052604090205460ff1661285957604051637e57b1e160e01b815260040160405180910390fd5b6001600160a01b03811660009081526007602052604090205460ff16612892576040516310cec38560e21b815260040160405180910390fd5b61289d600382615107565b50601b546001600160a01b038083166000818152600860209081526040808320949095168083529381528482205492825260138152848220848352905292909220546128eb92849291615132565b60405133906001600160a01b038316907f038a17b9b553c0c3fc2ed14b957a5d8420a1666fd2efe5c1b3fe5f23eea61bb390600090a350565b6060610cb660156147b2565b60008061293c83612507565b6022546001600160a01b038516600090815260296020526040902054919250906129669042615e4c565b1015610dbb5760008111612992576001600160a01b0383166000908152600a60205260409020546129cc565b6001600160a01b0383166000908152600b6020908152604080832054600a909252909120546129c2908390615ddd565b6129cc9190615dc9565b9150612637565b6017546001600160a01b031633146129fe576040516354348f0360e01b815260040160405180910390fd5b60208181556040518281527fc8d443472c9783cc36f8f5f5091f08ce9f37fc2f9e6d79cf1d9aaf40a433fee29101611205565b6001600160a01b038281166000908152600160205260409020548391163314612a6d57604051636efb4f4160e11b815260040160405180910390fd5b816001600160a01b0316836001600160a01b03161415612aa05760405163afe7ad4960e01b815260040160405180910390fd5b6001600160a01b038381166000818152602c6020908152604080832080546001600160a01b0319169588169586179055602d825280832094835293905282902042905590517fff0456758201108de53c0ff04c69988d4678ff455b2ce6f733328cf85722c04c90612b12908590615c42565b60405180910390a2505050565b6060610cb660036147b2565b6017546001600160a01b03163314612b56576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b038116612b7d5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415612bde576040516001600160a01b0382169083156108fc029084906000818181858888f19350505050158015612bd8573d6000803e3d6000fd5b50612bf2565b612bf26001600160a01b0384168284614f9e565b604080516001600160a01b0385811682526020820185905283168183015290517f9a3055ded8c8b5f21bbf4946c5afab6e1fa8b3f057922658e5e1ade125fb0b1e9181900360600190a1505050565b6017546001600160a01b03163314612c6c576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166000908152601a602052604090205460ff1615612ca65760405163274e25dd60e11b815260040160405180910390fd5b6001600160a01b0381166000908152601a602052604090819020805460ff19166001179055517f8addc69f897ecca0e41d70ed4ff9d75a9148a615a0fbda8597e53aea2684302f90611205908390615c42565b6001600160a01b038381166000908152600160205260409020548491163314612d3557604051636efb4f4160e11b815260040160405180910390fd5b6001600160a01b038216612d5c5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03808516600090815260136020908152604080832093871683529290522054612d9f5760405163184c088160e21b815260040160405180910390fd5b6001600160a01b038085166000908152601260209081526040808320938716835292905220544211612de4576040516327cfdcb760e01b815260040160405180910390fd5b6001600160a01b03841660009081526007602052604090205460ff1615612e1e576040516362e6201d60e01b815260040160405180910390fd5b6001600160a01b0380851660008181526013602090815260408083209488168084529482528083208054908490559383526012825280832085845290915281205590612e6b908483614f9e565b826001600160a01b0316846001600160a01b0316866001600160a01b03167ffdb7893bf11f50c621e59cc7f1cf540e94295cb27ca869ec7ed7618ca792886284604051612eba91815260200190565b60405180910390a45050505050565b60026000541415612eec5760405162461bcd60e51b81526004016117be90615d4b565b600260009081553381526007602052604090205460ff1615612f21576040516362e6201d60e01b815260040160405180910390fd5b612f2c6015336147c6565b15612f4a5760405163d7229c4360e01b815260040160405180910390fd5b601f54612f579042615db1565b3360009081526011602090815260408083206001600160a01b03871680855292528083209390935591516370a0823160e01b81529091906370a0823190612fa2903090600401615c42565b60206040518083038186803b158015612fba57600080fd5b505afa158015612fce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff29190615bdf565b90506130096001600160a01b03841633308561506c565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190613037903090600401615c42565b60206040518083038186803b15801561304f57600080fd5b505afa158015613063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130879190615bdf565b6130919190615e4c565b336000908152601460209081526040808320805460ff19166001179055601082528083206001600160a01b03881684529091528120805492945084929091906130db908490615db1565b90915550506040518281526001600160a01b0384169033907fa7e66869262026842e8d81f5e6806cdc8d846e27c824e2e22f4fe51442771b349060200160405180910390a35050600160005550565b6020546131379042615db1565b3360008181526012602090815260408083206001600160a01b03881680855290835281842095909555928252600881528282209382529290925281208054839290613183908490615e4c565b90915550503360009081526013602090815260408083206001600160a01b0386168452909152812080548392906131bb908490615db1565b90915550506040518181526001600160a01b0383169033907f9aaab310d247ad45aef26bbdefc4ebf20c728fdb84c92b95b2b05d21826940de90602001611703565b6017546001600160a01b03163314613228576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b03811660009081526019602052604090205460ff16613261576040516336fe17e760e21b815260040160405180910390fd5b6001600160a01b03811660009081526019602052604090819020805460ff19169055517f3ed8cbce8cab40e59282f1743e2b607effa08b5cbe0111bb4721134f2f80d02590611205908390615c42565b6017546001600160a01b031633146132dc576040516354348f0360e01b815260040160405180910390fd5b601880546001600160a01b0319166001600160a01b0383161790556040517fe987aaedf9d279143bdf1eee16cf1d0feb47742867d81083df8d6cd0a5ac857f90611205908390615c42565b6001600160a01b03818116600090815260016020526040902054829116331461336357604051636efb4f4160e11b815260040160405180910390fd5b6001600160a01b03831660009081526007602052604090205460ff16806133a257506001600160a01b03821660009081526007602052604090205460ff165b156133c05760405163ad2fdf3b60e01b815260040160405180910390fd5b6001600160a01b038381166000908152602c60205260409020548116908316146133fd57604051630ced616b60e21b815260040160405180910390fd5b6001600160a01b038084166000908152602d602090815260408083209386168352929052205461342f90603c90615db1565b42101561344f576040516356248e9760e01b815260040160405180910390fd5b6134588361500e565b6134618261500e565b6001600160a01b0383166000908152600c602052604081206134829061511c565b1115613564576001600160a01b0383166000908152600c602052604081206134aa9082615126565b6001600160a01b03808616600090815260096020818152604080842085871680865290835281852054958a1685529282528084209284529190528120805493945091926134f8908490615db1565b90915550506001600160a01b0380851660008181526009602090815260408083209486168352938152838220829055918152600c9091522061353a9082615107565b506001600160a01b0383166000908152600c6020526040902061355d9082614ff9565b5050613461565b6001600160a01b0383166000908152600d602052604081206135859061511c565b1115613667576001600160a01b0383166000908152600d602052604081206135ad9082615126565b6001600160a01b03808616600090815260286020818152604080842085871680865290835281852054958a1685529282528084209284529190528120805493945091926135fb908490615db1565b90915550506001600160a01b038085166000908152602860209081526040808320858516845282528083208390559286168252600d90522061363d9082614ff9565b506001600160a01b0384166000908152600d602052604090206136609082615107565b5050613564565b6001600160a01b038084166000908152600b602052604080822054928516825281208054909190613699908490615db1565b90915550506001600160a01b038084166000908152600b60209081526040808320839055600a909152808220549285168252812080549091906136dd908490615db1565b90915550506001600160a01b0383166000908152600a602090815260408083208390556029909152812055613713601584615107565b506001600160a01b03808416600081815260016020908152604080832080546001600160a01b031990811690915560028352818420805482169055602d8352818420958816808552958352818420849055938352602c909152908190208054909216909155517f9b712b63e3fb1325fa042d3c238ce8144937875065900528ea1e4f3b00f379f290612b12908690615c42565b6017546001600160a01b031633146137d1576040516354348f0360e01b815260040160405180910390fd5b60238190556040518181527fbdcfd7b8482f31cff6a87c362d9e2e3887f4cdc2018c7c485d8e78a7b2fadb6990602001611205565b6017546001600160a01b03163314613831576040516354348f0360e01b815260040160405180910390fd5b61383c602682614ff9565b6138595760405163f25e6b9f60e01b815260040160405180910390fd5b806001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561389257600080fd5b505afa1580156138a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ca9190615939565b6001600160a01b038281166000908152600e60205260409081902080546001600160a01b0319169383169384179055601d54905163696a437b60e01b815291169163696a437b9161391e9190600401615c42565b60206040518083038186803b15801561393657600080fd5b505afa15801561394a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396e9190615b68565b6001600160a01b0382166000908152600f60205260409020805460ff191691151591909117905561399e81611210565b6001600160a01b0382166000908152602b60209081526040918290208351815492850151600690810b66ffffffffffffff908116600160381b026001600160701b03199095169290910b161791909117815591810151600190920191909155517fabfa8db4d238fa78bf4e15fcc91328dd35f3978f200e2857a56bb719732b7b0b90611205908390615c42565b6017546001600160a01b03163314613a56576040516354348f0360e01b815260040160405180910390fd5b601f8190556040518181527fd319ef78d2b690bb773fcccc2d096306bac7c9222dd0bb6b300f461e4a376b4390602001611205565b3360009081526019602052604090205460ff16613abb57604051637e57b1e160e01b815260040160405180910390fd5b6001600160a01b03841660009081526007602052604090205460ff16613af4576040516310cec38560e21b815260040160405180910390fd5b613b0084848484615132565b336001600160a01b0385167f10a73de7ab6e9023aa6e2bc23f7abf4dcef591487e7e55f44c00e34fe60d56db613b368486615db1565b60405190815260200160405180910390a350505050565b613b586015826147c6565b15613b7657604051630809740d60e01b815260040160405180910390fd5b6001600160a01b03811660009081526014602052604090205460ff1615613bb057604051632f3d320560e01b815260040160405180910390fd5b613bbb601582614ff9565b506001600160a01b03811660008181526001602052604080822080546001600160a01b03191633908117909155905190917fed3faef50715743626cd57de74281a2b17cdbfc11c0486feda541fb911e0293d91a350565b6017546001600160a01b03163314613c3d576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b038116613c645760405163d92e233d60e01b815260040160405180910390fd5b601c80546001600160a01b0319166001600160a01b0383161790556040517feb931b4b5a98d20a6b1e6693a7c59d8e337a06e2f1473bb776e19251db7ae25090611205908390615c42565b6017546001600160a01b03163314613cda576040516354348f0360e01b815260040160405180910390fd5b62015180811015613cfe57604051633f384aad60e21b815260040160405180910390fd5b60228190556040518181527f54aafa56429e22230b52f1495588ffc632277d74f3a85ec755e13ac50c1584d990602001611205565b60026000541415613d565760405162461bcd60e51b81526004016117be90615d4b565b600260009081556001600160a01b03858116825260016020526040909120548591163314613d9757604051636efb4f4160e11b815260040160405180910390fd5b6001600160a01b03808616600090815260256020908152604080832093881683529290522054613dc990603c90615db1565b4211613de857604051631e0b407560e01b815260040160405180910390fd5b6001600160a01b03808616600090815260096020908152604080832093881683529290522054831115613e2e5760405163024ae82d60e61b815260040160405180910390fd5b6001600160a01b03851660009081526007602052604090205460ff1615613e685760405163ad2fdf3b60e01b815260040160405180910390fd5b6001600160a01b03808616600090815260096020908152604080832093881683529290529081208054859290613e9f908490615e4c565b90915550613eb990506001600160a01b0385168385614f9e565b6001600160a01b03808616600090815260096020908152604080832093881683529290522054613f07576001600160a01b0385166000908152600c60205260409020613f059085615107565b505b816001600160a01b0316846001600160a01b0316866001600160a01b03167f53e982dd9ec088d634c74c98fbbc161f808b4b6469a26c657120b9a31cb34bfe86604051613f5691815260200190565b60405180910390a450506001600055505050565b3360008181526007602052604090205460ff1615613f9b5760405163ad2fdf3b60e01b815260040160405180910390fd5b6001600160a01b03831660009081526007602052604090205460ff1615613fd5576040516362e6201d60e01b815260040160405180910390fd5b613fe06015826147c6565b613ffc5760405162941a5760e11b815260040160405180910390fd5b6001600160a01b038082166000908152600960209081526040808320938816835292905220548211156140425760405163356680b760e01b815260040160405180910390fd5b6001600160a01b03808216600090815260096020908152604080832093881683529290529081208054849290614079908490615e4c565b9091555061409390506001600160a01b0385168484614f9e565b826001600160a01b0316816001600160a01b0316856001600160a01b0316600080516020615f56833981519152856140c9614e6d565b6040805192835260208301919091520160405180910390a450505050565b6017546001600160a01b03163314614112576040516354348f0360e01b815260040160405180910390fd5b60218190556040518181527f24d51b415694a791b1c77df7817c075ac82b83ce611bcd8627d2e66cf37aa3e790602001611205565b6017546001600160a01b03163314614172576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166141995760405163d92e233d60e01b815260040160405180910390fd5b601b80546001600160a01b0319166001600160a01b0383161790556040517f1d1a3e7caf0717056e48dc8aefa54d806c7af86324fece4e5d49f8e1f01f84bf90611205908390615c42565b6017546001600160a01b0316331461420f576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166000908152601a602052604090205460ff1661424857604051633ca0d42760e11b815260040160405180910390fd5b6001600160a01b0381166000908152601a602052604090819020805460ff19169055517f5e8bd21d0a98cb2caf33706e56139ff40ffbdca7ec5d9d412a0a2292496dc70e90611205908390615c42565b3360009081526019602052604090205460ff166142c857604051637e57b1e160e01b815260040160405180910390fd5b6001600160a01b03831660009081526007602052604090205460ff16614301576040516310cec38560e21b815260040160405180910390fd5b6001600160a01b0383166000908152600c6020526040902061432390836147c6565b61434057604051632eda7a1160e01b815260040160405180910390fd5b6001600160a01b038084166000908152600960209081526040808320938616835292905220548111156143855760405162919bed60e01b815260040160405180910390fd5b60175460405163a9059cbb60e01b81526001600160a01b038481169263a9059cbb926143b992909116908590600401615cb2565b602060405180830381600087803b1580156143d357600080fd5b505af1925050508015614403575060408051601f3d908101601f1916820190925261440091810190615b68565b60015b61440c5761440e565b505b6001600160a01b03808416600090815260096020908152604080832093861683529290529081208054839290614445908490615e4c565b90915550506001600160a01b03808416600090815260096020908152604080832093861683529290522054614498576001600160a01b0383166000908152600c602052604090206144969083615107565b505b336001600160a01b0316836001600160a01b03167f20262b97130b5cb8f80624eed2733df2b05db4a0789b4a3d0157e1d318333104848460405161277f929190615cb2565b336000908152601a602052604090205460ff1661450d57604051630942721960e31b815260040160405180910390fd5b6001600160a01b03811660009081526007602052604090205460ff1615614547576040516304ee891b60e11b815260040160405180910390fd5b6001600160a01b038116600081815260076020526040808220805460ff19166001179055513392917f070125a1c0f5202217aae14ec399abfaaa13c2fd98a91d43bd3a897dd4751e8091a350565b600061459f614e6d565b602e556145ad6003876147c6565b80156145de57506001600160a01b038087166000908152600860209081526040808320938916835292905220548411155b801561460257506001600160a01b0386166000908152600560205260409020548311155b801561463157506001600160a01b038616600090815260066020526040902054829061462e9042615e4c565b10155b15614675577f4851cad52e624c8f7a1d44c28a80db05988ba2451fc0db6b0ec338d8eca95afb602e5460405161466991815260200190565b60405180910390a15060015b95945050505050565b6017546001600160a01b031633146146a9576040516354348f0360e01b815260040160405180910390fd5b6146b46015836147c6565b6146d157604051636211d34960e01b815260040160405180910390fd5b6146da8261500e565b6001600160a01b0382166000908152600a602052604081208054839290614702908490615db1565b90915550506001600160a01b038216600081815260296020908152604080832054600a909252918290205491517f5abcf5031fdbd3badb9d1e09094208de329aee72730e87650f346584205d23d192614762928252602082015260400190565b60405180910390a25050565b60006022548261477e9190615eaa565b610dbb9083615e4c565b6000602254831015612637576022546147a18385615ddd565b6147ab9190615dc9565b9050610dbb565b606060006147bf83615288565b9392505050565b6001600160a01b038116600090815260018301602052604081205415156147bf565b6000610dbb826022546023546152e4565b6002600054141561481c5760405162461bcd60e51b81526004016117be90615d4b565b600260009081556001600160a01b0384168152600d6020526040902061484290836147c6565b61485e576040516241cfa560e21b815260040160405180910390fd5b6001600160a01b038084166000908152602860209081526040808320938616835292905220548111156148a45760405163435b562560e01b815260040160405180910390fd5b6148ad83615392565b60006148bc610dab8385614a07565b6001600160a01b0385166000908152600b602052604090205490915015614972576001600160a01b0384166000908152600b6020908152604080832054600a9092529091205461490d908390615ddd565b6149179190615dc9565b6001600160a01b0385166000908152600a60205260408120805490919061493f908490615e4c565b90915550506001600160a01b0384166000908152600b60205260408120805483929061496c908490615e4c565b90915550505b6001600160a01b038085166000908152602860209081526040808320938716835292905290812080548492906149a9908490615e4c565b90915550506001600160a01b038085166000908152602860209081526040808320938716835292905220546149fc576001600160a01b0384166000908152600d602052604090206149fa9084615107565b505b505060016000555050565b6001600160a01b0381166000908152602b602052604081206001015415610dbb576001600160a01b0382166000908152600f602052604081205460ff16614a79576001600160a01b0383166000908152602b6020526040902054614a7490600160381b900460060b615ebe565b614a9d565b6001600160a01b0383166000908152602b6020526040902054600160381b900460060b5b601d5460225460405163a0d2710760e01b81529293506001600160a01b039091169163a0d2710791614ad59188918691600401615d82565b60206040518083038186803b158015614aed57600080fd5b505afa158015614b01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca29190615bdf565b6000614b304261476e565b6001600160a01b03831660009081526029602052604090205410156115d157614b6060225442610bc69190615e4c565b6001600160a01b03831660009081526029602052604090205411614bd657614b8782615392565b6001600160a01b0382166000908152600b6020908152604080832054600a90925290912055614bb54261476e565b6001600160a01b038316600090815260296020526040902055506001919050565b6022546001600160a01b038316600090815260296020526040902054614bfc9042615e4c565b10614c5857614c0a82615392565b6001600160a01b0382166000908152600b6020908152604080832054600a83528184205560225460299092528220805491929091614c49908490615db1565b90915550600191506115d19050565b614c614261476e565b6001600160a01b0383166000908152602a602052604090205410156115d1576001600160a01b0382166000908152600b6020526040902054614ca283615392565b6001600160a01b0383166000908152600b6020908152604080832054600a909252909120548291614cd291615ddd565b614cdc9190615dc9565b6001600160a01b0384166000908152600a602052604090205550919050565b6001600160a01b038116600090815260296020526040902054614d4090614d229042615e4c565b6001600160a01b0383166000908152600b6020526040902054614788565b6001600160a01b0382166000908152600a602052604081208054909190614d68908490615db1565b90915550506001600160a01b03166000908152602960205260409020429055565b6001600160a01b0383166000908152600a6020526040902054811115614dc25760405163356680b760e01b815260040160405180910390fd5b6001600160a01b0383166000908152602a60209081526040808320429055600a90915281208054839290614df7908490615e4c565b90915550506001600160a01b038083166000908152600860209081526040808320601b5490941683529290529081208054839290614e36908490615db1565b90915550506001600160a01b03821660009081526005602052604081208054839290614e63908490615db1565b9091555050505050565b6000603f5a614e7d906040615ddd565b610cb69190615dc9565b6001600160a01b038216600090815260066020526040812054614ec0576001600160a01b03831660009081526006602052604090204290555b614ecb600384614ff9565b50506001600160a01b03808316600081815260106020908152604080832094861680845294825280832080549084905593835260088252808320948352939052918220805491928392614f1f908490615db1565b9091555050601b546001600160a01b0383811691161415610dbb57601b54604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b158015614f8057600080fd5b505af1158015614f94573d6000803e3d6000fd5b5050505092915050565b614ff48363a9059cbb60e01b8484604051602401614fbd929190615cb2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526153b7565b505050565b60006147bf836001600160a01b038416615489565b61501781614b25565b5061502181614cfb565b6001600160a01b0381166000908152600a6020908152604080832054600b9092529091205461505091906154d8565b6001600160a01b039091166000908152600a6020526040902055565b6040516001600160a01b03808516602483015283166044820152606481018290526150a49085906323b872dd60e01b90608401614fbd565b50505050565b6000808486602e546150bc9190615e4c565b6150c69190615db1565b9050670de0b6b3a7640000846127106150df8685615ddd565b6150e99190615dc9565b6150f39190615ddd565b6150fd9190615dc9565b9695505050505050565b60006147bf836001600160a01b0384166154ee565b6000610dbb825490565b60006147bf83836155e1565b601b546001600160a01b0384811691161461520a576017546001600160a01b038085169163a9059cbb91166151678486615db1565b6040518363ffffffff1660e01b8152600401615184929190615cb2565b602060405180830381600087803b15801561519e57600080fd5b505af19250505080156151ce575060408051601f3d908101601f191682019092526151cb91810190615b68565b60015b615208573d8080156151fc576040519150601f19603f3d011682016040523d82523d6000602084013e615201565b606091505b505061520a565b505b6001600160a01b03808516600090815260086020908152604080832093871683529290529081208054849290615241908490615e4c565b90915550506001600160a01b0380851660009081526013602090815260408083209387168352929052908120805483929061527d908490615e4c565b909155505050505050565b6060816000018054806020026020016040519081016040528092919081815260200182805480156152d857602002820191906000526020600020905b8154815260200190600101908083116152c4575b50505050509050919050565b60008080600019858709858702925082811083820303915050806000141561531e576000841161531357600080fd5b5082900490506147bf565b80841161532a57600080fd5b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b61539b8161560b565b6001600160a01b039091166000908152600b6020526040902055565b600061540c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166157ef9092919063ffffffff16565b805190915015614ff4578080602001905181019061542a9190615b68565b614ff45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016117be565b60008181526001830160205260408120546154d057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610dbb565b506000610dbb565b60008183106154e757816147bf565b5090919050565b600081815260018301602052604081205480156155d7576000615512600183615e4c565b855490915060009061552690600190615e4c565b905081811461558b57600086600001828154811061554657615546615f27565b906000526020600020015490508087600001848154811061556957615569615f27565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061559c5761559c615f11565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610dbb565b6000915050610dbb565b60008260000182815481106155f8576155f8615f27565b9060005260206000200154905092915050565b60006156164261476e565b601e546001600160a01b03166000908152602b6020526040902060010154146156ad57601e5461564e906001600160a01b0316611210565b601e546001600160a01b03166000908152602b60209081526040918290208351815492850151600690810b66ffffffffffffff908116600160381b026001600160701b03199095169290910b1617919091178155910151600191909101555b60005b6001600160a01b0383166000908152600d602052604090206156d19061511c565b811015612637576001600160a01b0383166000908152600d602052604081206156fa9083615126565b90506157076026826147c6565b156157dc576157154261476e565b6001600160a01b0382166000908152602b60205260409020600101541461579b5761573f81611210565b6001600160a01b0382166000908152602b60209081526040918290208351815492850151600690810b66ffffffffffffff908116600160381b026001600160701b03199095169290910b16179190911781559101516001909101555b6001600160a01b038085166000908152602860209081526040808320938516835292905220546157cf90610dab9083614a07565b6157d99084615db1565b92505b50806157e781615e8f565b9150506156b0565b6060610ca2848460008585843b6158485760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016117be565b600080866001600160a01b031685876040516158649190615c26565b60006040518083038185875af1925050503d80600081146158a1576040519150601f19603f3d011682016040523d82523d6000602084013e6158a6565b606091505b50915091506158b68282866158c1565b979650505050505050565b606083156158d05750816147bf565b8251156158e05782518084602001fd5b8160405162461bcd60e51b81526004016117be9190615d18565b805180151581146115d157600080fd5b8051600681900b81146115d157600080fd5b60006020828403121561592e57600080fd5b81356147bf81615f3d565b60006020828403121561594b57600080fd5b81516147bf81615f3d565b6000806040838503121561596957600080fd5b823561597481615f3d565b9150602083013561598481615f3d565b809150509250929050565b6000806000606084860312156159a457600080fd5b83356159af81615f3d565b925060208401356159bf81615f3d565b915060408401356159cf81615f3d565b809150509250925092565b6000806000606084860312156159ef57600080fd5b83356159fa81615f3d565b92506020840135615a0a81615f3d565b929592945050506040919091013590565b60008060008060808587031215615a3157600080fd5b8435615a3c81615f3d565b93506020850135615a4c81615f3d565b9250604085013591506060850135615a6381615f3d565b939692955090935050565b60008060008060808587031215615a8457600080fd5b8435615a8f81615f3d565b93506020850135615a9f81615f3d565b93969395505050506040820135916060013590565b600080600080600060a08688031215615acc57600080fd5b8535615ad781615f3d565b94506020860135615ae781615f3d565b94979496505050506040830135926060810135926080909101359150565b60008060408385031215615b1857600080fd5b8235615b2381615f3d565b946020939093013593505050565b600080600060608486031215615b4657600080fd5b8335615b5181615f3d565b92506020840135915060408401356159cf81615f3d565b600060208284031215615b7a57600080fd5b6147bf826158fa565b600080600060608486031215615b9857600080fd5b615ba18461590a565b9250615baf6020850161590a565b9150615bbd604085016158fa565b90509250925092565b600060208284031215615bd857600080fd5b5035919050565b600060208284031215615bf157600080fd5b5051919050565b600080600060608486031215615c0d57600080fd5b8351925060208401519150604084015190509250925092565b60008251615c38818460208701615e63565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b81811015615ca557845163ffffffff1683529383019391830191600101615c83565b5090979650505050505050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015615d0c5783516001600160a01b031683529284019291840191600101615ce7565b50909695505050505050565b6020815260008251806020840152615d37816040850160208701615e63565b601f01601f19169190910160400192915050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b92835260069190910b6020830152604082015260600190565b9283526020830191909152604082015260600190565b60008219821115615dc457615dc4615ee5565b500190565b600082615dd857615dd8615efb565b500490565b6000816000190483118215151615615df757615df7615ee5565b500290565b60008160060b8360060b6000811281667fffffffffffff1901831281151615615e2757615e27615ee5565b81667fffffffffffff018313811615615e4257615e42615ee5565b5090039392505050565b600082821015615e5e57615e5e615ee5565b500390565b60005b83811015615e7e578181015183820152602001615e66565b838111156150a45750506000910152565b6000600019821415615ea357615ea3615ee5565b5060010190565b600082615eb957615eb9615efb565b500690565b60008160060b667fffffffffffff19811415615edc57615edc615ee5565b60000392915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0381168114615f5257600080fd5b5056fe46f2180879a7123a197cc3828c28955d70d661c70acbdc02450daf5f9a9c1cfaee3f0daba9837d1ab0597acf34328550e4832d02e24e467825e7c2dd318c3820a2646970667358221220a652922e4d7790b0f864618e6193f295e00a8e3132caf1f7755731c5f43e8adb64736f6c6343000807003300000000000000000000000054054ea2db6edc336cb87966815fd66cc337f224000000000000000000000000d36ac9ff5562abb541f51345f340fb650547a6610000000000000000000000001ceb5cb57c4d4e2b2433641b95dd330a33185a44000000000000000000000000976b01c02c636dd5901444b941442fd70b86dcd500000000000000000000000011b7a6bc0259ed6cf9db8f499988f9ecc7167bf5

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103ec5760003560e01c806390a4684e1161020d578063c5198abc11610121578063c5198abc146109e1578063c7ae40d0146109f4578063cb4be2bb14610a07578063cb54694d14610a1a578063cd22af1b14610a2d578063d55995fe14610a58578063dd2080d614610a6b578063ddca3f4314610a7e578063e326ac4314610a87578063ebbb619414610aa7578063ec00cdfc14610aba578063ec8ca64314610acd578063f0f346b914610af6578063f11a1d1a14610b09578063f136a09d14610b1c578063f25e311b14610b3c578063f39c38a014610b4f578063f75f9f7b14610b62578063f9d46cf214610b75578063fc253d2b14610b88578063fe75bc4614610b9157600080fd5b806390a4684e146107f4578063951dc22c14610807578063966abd001461080f57806398e90a0f146108225780639d5c33d81461084b578063a21458091461085e578063a39744b514610871578063a515366a1461089c578063a5d059ca146108af578063a676f9ff146108c2578063a7d2e784146108e2578063aac6aa9c146108eb578063ab033ea9146108fe578063af320e8114610911578063b0103b1a14610924578063b239223314610947578063b440027f1461095a578063b600702a14610985578063b7e7734014610998578063b87fcbff146109ab578063c20297f0146109ce57600080fd5b806359a2255e1161030457806359a2255e146106505780635aa6e675146106635780635ebe23f0146106765780635feeb7941461067f578063633fb68f1461069257806364bb43ee1461069b57806368a9f19c146106ae578063694798e6146106c157806369fe0e2d146106ec5780636ba42aaa146106ff5780636cf262bc146107125780636e2a9ca61461072557806372da828a1461073857806374a8f1031461074b578063768b5d901461075e5780637b40c913146107675780637c8fce231461077a578063878c723e146107825780638bb6dfa8146107ab5780638cb22b76146107be5780638fe204dd146107e157600080fd5b8063034d4c61146103f157806307b435c2146104175780630c620bce146104425780630d6a1f87146104575780631101eb411461046a57806311466d721461047f57806315006b8214610492578063160e1e31146104bd578063165e62e7146104d0578063168f92e71461050d5780631b44555e146105385780631c5a9d9c146105585780631ef94b911461056b57806321040b011461058b578063238efcbc146105b6578063274a8db4146105be57806351cff8d9146105f157806352a4de291461060457806355ea6c4714610617578063575288bf1461062a578063594a3a931461063d575b600080fd5b6104046103ff36600461591c565b610ba4565b6040519081526020015b60405180910390f35b610404610425366004615956565b601260209081526000928352604080842090915290825290205481565b61044a610caa565b60405161040e9190615ccb565b610404610465366004615b05565b610cbb565b61047d6104783660046159da565b610dc1565b005b61047d61048d366004615b05565b610f1b565b6104046104a0366004615956565b601060209081526000928352604080842090915290825290205481565b61047d6104cb36600461591c565b6110aa565b6104e36104de36600461591c565b611210565b604080518251600690810b825260208085015190910b90820152918101519082015260600161040e565b61040461051b366004615956565b600960209081526000928352604080842090915290825290205481565b61040461054636600461591c565b60056020526000908152604090205481565b61047d61056636600461591c565b6115d6565b601b5461057e906001600160a01b031681565b60405161040e9190615c42565b610404610599366004615956565b601360209081526000928352604080842090915290825290205481565b61047d61170f565b6105e16105cc36600461591c565b601a6020526000908152604090205460ff1681565b604051901515815260200161040e565b61047d6105ff36600461591c565b61179b565b61047d6106123660046159da565b6119a4565b61047d61062536600461591c565b611bd5565b61047d6106383660046159da565b611c89565b61047d61064b366004615956565b611f4c565b61047d61065e36600461591c565b611ff1565b60175461057e906001600160a01b031681565b610404601f5481565b61047d61068d36600461591c565b6120a3565b61040460215481565b61047d6106a936600461591c565b61230d565b61047d6106bc36600461591c565b61238f565b6104046106cf366004615956565b602860209081526000928352604080842090915290825290205481565b61047d6106fa366004615bc6565b612447565b6105e161070d36600461591c565b6124a7565b61040461072036600461591c565b612507565b61047d6107333660046159da565b61263d565b61047d61074636600461591c565b61278c565b61047d61075936600461591c565b612829565b61040460225481565b601e5461057e906001600160a01b031681565b61044a612924565b61057e61079036600461591c565b6001602052600090815260409020546001600160a01b031681565b6104046107b936600461591c565b612930565b6105e16107cc36600461591c565b60146020526000908152604090205460ff1681565b61047d6107ef366004615bc6565b6129d3565b61047d610802366004615956565b612a31565b61044a612b1f565b61047d61081d366004615b31565b612b2b565b61057e61083036600461591c565b6002602052600090815260409020546001600160a01b031681565b61047d61085936600461591c565b612c41565b61047d61086c36600461598f565b612cf9565b61040461087f366004615956565b600860209081526000928352604080842090915290825290205481565b61047d6108aa366004615b05565b612ec9565b61047d6108bd366004615b05565b61312a565b6104046108d036600461591c565b60296020526000908152604090205481565b61040460205481565b61047d6108f936600461591c565b6131fd565b61047d61090c36600461591c565b6132b1565b61047d61091f366004615956565b613327565b6105e161093236600461591c565b60076020526000908152604090205460ff1681565b61047d610955366004615bc6565b6137a6565b610404610968366004615956565b602560209081526000928352604080842090915290825290205481565b61047d61099336600461591c565b613806565b61047d6109a6366004615bc6565b613a2b565b6105e16109b936600461591c565b60196020526000908152604090205460ff1681565b61047d6109dc366004615a6e565b613a8b565b61047d6109ef36600461591c565b613b4d565b601c5461057e906001600160a01b031681565b61047d610a1536600461591c565b613c12565b61047d610a28366004615bc6565b613caf565b610404610a3b366004615956565b601160209081526000928352604080842090915290825290205481565b61047d610a66366004615a1b565b613d33565b61047d610a793660046159da565b613f6a565b61040460245481565b610404610a9536600461591c565b60066020526000908152604090205481565b61047d610ab5366004615bc6565b6140e7565b61047d610ac836600461591c565b614147565b61057e610adb36600461591c565b602c602052600090815260409020546001600160a01b031681565b61047d610b0436600461591c565b6141e4565b601d5461057e906001600160a01b031681565b610404610b2a36600461591c565b602a6020526000908152604090205481565b61047d610b4a3660046159da565b614298565b60185461057e906001600160a01b031681565b61047d610b7036600461591c565b6144dd565b6105e1610b83366004615ab4565b614595565b61040460235481565b61047d610b9f366004615b05565b61467e565b600080610bb083612507565b6022549091504290610bcb90610bc69083615e4c565b61476e565b6001600160a01b0385166000908152602960205260409020541115610c6f576022546001600160a01b038516600090815260296020526040902054610c109042615e4c565b10610c4c576022546001600160a01b038516600090815260296020526040902054610c3b9190615db1565b610c459082615e4c565b9050610c85565b6001600160a01b038416600090815260296020526040902054610c459082615e4c565b610c784261476e565b610c829082615e4c565b90505b610c8f8183614788565b610c9885612930565b610ca29190615db1565b949350505050565b6060610cb660266147b2565b905090565b6000610cc86026846147c6565b15610dbb576000610cd884611210565b90508060400151600014610db9576001600160a01b0384166000908152600f602052604081205460ff16610d19578160200151610d1490615ebe565b610d1f565b81602001515b601d5460225460405163a0d2710760e01b8152929350610db0926001600160a01b039092169163a0d2710791610d5b9189918791600401615d82565b60206040518083038186803b158015610d7357600080fd5b505afa158015610d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dab9190615bdf565b6147e8565b92505050610dbb565b505b92915050565b6001600160a01b038381166000908152600160205260409020548491163314610dfd57604051636efb4f4160e11b815260040160405180910390fd5b602054610e0a9042615db1565b6001600160a01b03808616600081815260126020908152604080832094891680845294825280832095909555918152601382528381209281529190529081208054849290610e59908490615db1565b90915550610e6a90508484846147f9565b6001600160a01b038085166000908152602860209081526040808320938716835292905220548015801590610ea95750602154610ea78286614a07565b105b15610ec757604051636f447fcd60e11b815260040160405180910390fd5b836001600160a01b0316856001600160a01b03167f9aaab310d247ad45aef26bbdefc4ebf20c728fdb84c92b95b2b05d21826940de85604051610f0c91815260200190565b60405180910390a35050505050565b3360008181526007602052604090205460ff1615610f4c5760405163ad2fdf3b60e01b815260040160405180910390fd5b610f576015826147c6565b610f735760405162941a5760e11b815260040160405180910390fd5b610f7c81614b25565b15610fd7576001600160a01b038116600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f7683398151915293610fce9390929091615d9b565b60405180910390a25b6001600160a01b0381166000908152600a60205260409020548211156110565761100081614cfb565b6001600160a01b038116600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f768339815191529361104d9390929091615d9b565b60405180910390a25b611061818484614d89565b601b546001600160a01b03808516918382169116600080516020615f568339815191528561108d614e6d565b6040805192835260208301919091520160405180910390a4505050565b6017546001600160a01b031633146110d5576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166110fc5760405163d92e233d60e01b815260040160405180910390fd5b601e80546001600160a01b038084166001600160a01b031992831681179093556000838152600e6020526040908190208054909316909317909155601d54915163696a437b60e01b815291169063696a437b9061115d908490600401615c42565b60206040518083038186803b15801561117557600080fd5b505afa158015611189573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ad9190615b68565b6001600160a01b0382166000908152600f602052604090819020805460ff191692151592909217909155517f9bb1515b0fc2645a3f011162460a22fdd512e0bca265e7dc9ba6bceae8930afa90611205908390615c42565b60405180910390a150565b60408051606081018252600080825260208201819052918101919091526112364261476e565b6001600160a01b0383166000908152602b602052604090206001015414156112ac57506001600160a01b03166000908152602b602090815260409182902082516060810184528154600681810b810b810b8352600160381b909104810b810b900b92810192909252600101549181019190915290565b6000806112c060225442610bc69190615e4c565b6001600160a01b0385166000908152602b602052604090206001015490915081141561142457604080516001808252818301909252600091602080830190803683375050506001600160a01b0386166000908152602b602052604090205490915060060b61132d4261476e565b6113379042615e4c565b8260008151811061134a5761134a615f27565b63ffffffff909216602092830291909101820152601d546001600160a01b038881166000908152600e90935260409283902054925163dc686d9160e01b81529181169263dc686d91926113a69291909116908690600401615c56565b60606040518083038186803b1580156113be57600080fd5b505afa1580156113d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f69190615b83565b600692830b90920b80885291955061141091839150615dfc565b600690810b900b6020860152506115ad9050565b6001600160a01b0384166000908152602b60205260409020600101548111156115ad576040805160028082526060820183526000926020830190803683370190505090506114714261476e565b61147b9042615e4c565b8160008151811061148e5761148e615f27565b602002602001019063ffffffff16908163ffffffff16815250506022546114b44261476e565b6114be9042615e4c565b6114c89190615db1565b816001815181106114db576114db615f27565b63ffffffff909216602092830291909101820152601d546001600160a01b038781166000908152600e909352604080842054905163dc686d9160e01b81529282169263dc686d91926115339216908690600401615c56565b60606040518083038186803b15801561154b57600080fd5b505afa15801561155f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115839190615b83565b600692830b90920b808852919550915061159e908290615dfc565b600690810b900b602086015250505b81156115c6576115bc4261476e565b60408401526115ce565b600060408401525b50505b919050565b3360009081526007602052604090205460ff1615611607576040516362e6201d60e01b815260040160405180910390fd5b3360009081526011602090815260408083206001600160a01b038516845290915290205461164857604051636258f48160e01b815260040160405180910390fd5b3360009081526011602090815260408083206001600160a01b0385168452909152902054421161168b57604051630fd0eeef60e11b815260040160405180910390fd5b3360008181526011602090815260408083206001600160a01b03861684529091528120819055906116bc9083614e87565b9050816001600160a01b0316336001600160a01b03167f3673530133b6da67e9854f605b0cfa7bb9798cd33c18036dfc10d8da7c4d4a758360405161170391815260200190565b60405180910390a35050565b6018546001600160a01b0316331461173a57604051637ef5703160e11b815260040160405180910390fd5b60188054601780546001600160a01b0383166001600160a01b031991821681179092559091169091556040517fc73be659241aade67e9a059bcf21494955018b213dbd1179054ccf928b13f3b69161179191615c42565b60405180910390a1565b600260005414156117c75760405162461bcd60e51b81526004016117be90615d4b565b60405180910390fd5b600260009081553381526013602090815260408083206001600160a01b038516845290915290205461180c5760405163184c088160e21b815260040160405180910390fd5b3360009081526012602090815260408083206001600160a01b0385168452909152902054421161184f576040516327cfdcb760e01b815260040160405180910390fd5b3360009081526007602052604090205460ff1615611880576040516362e6201d60e01b815260040160405180910390fd5b3360009081526013602090815260408083206001600160a01b0385811680865291909352922054601b5490929116141561191357601c5460405163140e25ad60e31b8152600481018390526001600160a01b039091169063a0712d6890602401600060405180830381600087803b1580156118fa57600080fd5b505af115801561190e573d6000803e3d6000fd5b505050505b3360008181526013602090815260408083206001600160a01b0387168085529083528184208490558484526012835281842081855290925282209190915561195b9183614f9e565b6040518181526001600160a01b0383169033907f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b63989060200160405180910390a350506001600055565b600260005414156119c75760405162461bcd60e51b81526004016117be90615d4b565b60026000556119d76026836147c6565b6119f45760405163e0b6aead60e01b815260040160405180910390fd5b6119ff6015846147c6565b611a1c57604051636211d34960e01b815260040160405180910390fd5b6001600160a01b0383166000908152600d60205260409020611a3e9083614ff9565b50611a488361500e565b6021546001600160a01b03808516600090815260286020908152604080832093871683529290522054611a8690611a80908490615db1565b84614a07565b1015611aa557604051636f447fcd60e11b815260040160405180910390fd5b6001600160a01b038316600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f7683398151915293611af29390929091615d9b565b60405180910390a2611b0f6001600160a01b03831633308461506c565b6001600160a01b03808416600090815260286020908152604080832093861683529290529081208054839290611b46908490615db1565b90915550611b599050610dab8284614a07565b6001600160a01b0384166000908152600b602052604081208054909190611b81908490615db1565b909155505060405181815233906001600160a01b0384811691908616907f4e186bc75a2220191b826baff3ee63c3e970e94e58a9007ff94c9a7b8e6ebb3f9060200160405180910390a45050600160005550565b336000908152601a602052604090205460ff16611c0557604051630942721960e31b815260040160405180910390fd5b6001600160a01b03811660009081526007602052604090205460ff16611c3e576040516310cec38560e21b815260040160405180910390fd5b6001600160a01b038116600081815260076020526040808220805460ff19169055513392917fe02b2375d8fb4aef3e5bc5d53bffcf70b6f185c5c93e69dcbe8b6cfc58e837e291a350565b60026000541415611cac5760405162461bcd60e51b81526004016117be90615d4b565b6002600055611cbc6015846147c6565b611cd957604051636211d34960e01b815260040160405180910390fd5b601b546001600160a01b0383811691161415611d075760405162822d9760e71b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190611d36903090600401615c42565b60206040518083038186803b158015611d4e57600080fd5b505afa158015611d62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d869190615bdf565b9050611d9d6001600160a01b03841633308561506c565b600081846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611dcc9190615c42565b60206040518083038186803b158015611de457600080fd5b505afa158015611df8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1c9190615bdf565b611e269190615e4c565b9050600061271060245483611e3b9190615ddd565b611e459190615dc9565b9050611e518183615e4c565b6001600160a01b038088166000908152600960209081526040808320938a1683529290529081208054909190611e88908490615db1565b90915550506001600160a01b0380871660009081526025602090815260408083208985168085529252909120429055601754611ec5921683614f9e565b6001600160a01b0386166000908152600c60205260409020611ee79086614ff9565b50336001600160a01b0316856001600160a01b0316876001600160a01b03167fec1a37d4a331a5059081e0fb5da1735e7890900cd215a4fb1e9f2779fd7b83eb85604051611f3791815260200190565b60405180910390a45050600160005550505050565b6001600160a01b038281166000908152600160205260409020548391163314611f8857604051636efb4f4160e11b815260040160405180910390fd5b6001600160a01b03838116600081815260026020908152604080832080546001600160a01b031916888716908117909155600190925280832054905191941692917fa8bad3f0b781e1d954af9945167d5f80bfe5e57930f17c93843187c77557a6b891a4505050565b6001600160a01b03818116600090815260026020526040902054829116331461202d5760405163cfe9663360e01b815260040160405180910390fd5b6001600160a01b03828116600081815260016020908152604080832080546002909352818420805487166001600160a01b031980861691909117909255805490911690555193169283929133917fcf30c54296d5eee76168b564c59c50578d49c271733a470f32707c8cfbc88a8b9190a4505050565b3360008181526007602052604090205460ff16156120d45760405163ad2fdf3b60e01b815260040160405180910390fd5b6120df6015826147c6565b6120fb5760405162941a5760e11b815260040160405180910390fd5b61210481614b25565b1561215f576001600160a01b038116600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f76833981519152936121569390929091615d9b565b60405180910390a25b601d546001600160a01b038381166000908152600860209081526040808320601b548516845290915280822054905163435b21c160e01b8152600481019190915290928392839291169063435b21c19060240160606040518083038186803b1580156121ca57600080fd5b505afa1580156121de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122029190615bf8565b9250925092506000612212614e6d565b90506000612222828486886150aa565b6001600160a01b0387166000908152600a60205260409020549091508111156122bc5761224e86614cfb565b6001600160a01b038616600081815260296020908152604080832054600a835281842054600b90935292819020549051600080516020615f768339815191529361229b9390929091615d9b565b60405180910390a26122ab614e6d565b91506122b9828486886150aa565b90505b6122c7868883614d89565b601b5460408051838152602081018590526001600160a01b038a8116938a821693911691600080516020615f56833981519152910160405180910390a450505050505050565b6017546001600160a01b03163314612338576040516354348f0360e01b815260040160405180910390fd5b612343602682615107565b61236057604051630a8d08b160e01b815260040160405180910390fd5b7f51199d699bdfd516fa88dd0d2f8487c40c147b4867acaa23adc8d4df6b098e56816040516112059190615c42565b6017546001600160a01b031633146123ba576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b03811660009081526019602052604090205460ff16156123f45760405163546da66560e11b815260040160405180910390fd5b6001600160a01b03811660009081526019602052604090819020805460ff19166001179055517f049ccb28ab796d3225573a065712f6e7754487ced56056cda8889c337511807b90611205908390615c42565b6017546001600160a01b03163314612472576040516354348f0360e01b815260040160405180910390fd5b60248190556040518181527f4c10ca068ff7002cf5da78f2f697d1e91f6f0ac27f7344b28e8ef25263f87e5d90602001611205565b60006124b1614e6d565b602e556124bf6003836147c6565b156115d1577f4851cad52e624c8f7a1d44c28a80db05988ba2451fc0db6b0ec338d8eca95afb602e546040516124f791815260200190565b60405180910390a1506001919050565b6000805b6001600160a01b0383166000908152600d6020526040902061252c9061511c565b811015612637576001600160a01b0383166000908152600d602052604081206125559083615126565b90506125626026826147c6565b1561262457600061257282611210565b90508060400151600014612622576001600160a01b0382166000908152600f602052604081205460ff166125b35781602001516125ae90615ebe565b6125b9565b81602001515b601d546001600160a01b03888116600090815260286020908152604080832089851684529091529081902054602254915163a0d2710760e01b815294955061261494929093169263a0d2710792610d5b928791600401615d82565b61261e9086615db1565b9450505b505b508061262f81615e8f565b91505061250b565b50919050565b3360009081526019602052604090205460ff1661266d57604051637e57b1e160e01b815260040160405180910390fd5b6001600160a01b03831660009081526007602052604090205460ff166126a6576040516310cec38560e21b815260040160405180910390fd5b6126b18383836147f9565b60175460405163a9059cbb60e01b81526001600160a01b038481169263a9059cbb926126e592909116908590600401615cb2565b602060405180830381600087803b1580156126ff57600080fd5b505af192505050801561272f575060408051601f3d908101601f1916820190925261272c91810190615b68565b60015b6127385761273a565b505b336001600160a01b0316836001600160a01b03167f6e10247c3c094d220ee99436c164b7f38d63b335a20ed817cbefaee4bb02d20e848460405161277f929190615cb2565b60405180910390a3505050565b6017546001600160a01b031633146127b7576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166127de5760405163d92e233d60e01b815260040160405180910390fd5b601d80546001600160a01b0319166001600160a01b0383161790556040517f71973fd672e51deb8f739b1f7e1eab991936645acd6f83e2bde6eeeaff5490b090611205908390615c42565b3360009081526019602052604090205460ff1661285957604051637e57b1e160e01b815260040160405180910390fd5b6001600160a01b03811660009081526007602052604090205460ff16612892576040516310cec38560e21b815260040160405180910390fd5b61289d600382615107565b50601b546001600160a01b038083166000818152600860209081526040808320949095168083529381528482205492825260138152848220848352905292909220546128eb92849291615132565b60405133906001600160a01b038316907f038a17b9b553c0c3fc2ed14b957a5d8420a1666fd2efe5c1b3fe5f23eea61bb390600090a350565b6060610cb660156147b2565b60008061293c83612507565b6022546001600160a01b038516600090815260296020526040902054919250906129669042615e4c565b1015610dbb5760008111612992576001600160a01b0383166000908152600a60205260409020546129cc565b6001600160a01b0383166000908152600b6020908152604080832054600a909252909120546129c2908390615ddd565b6129cc9190615dc9565b9150612637565b6017546001600160a01b031633146129fe576040516354348f0360e01b815260040160405180910390fd5b60208181556040518281527fc8d443472c9783cc36f8f5f5091f08ce9f37fc2f9e6d79cf1d9aaf40a433fee29101611205565b6001600160a01b038281166000908152600160205260409020548391163314612a6d57604051636efb4f4160e11b815260040160405180910390fd5b816001600160a01b0316836001600160a01b03161415612aa05760405163afe7ad4960e01b815260040160405180910390fd5b6001600160a01b038381166000818152602c6020908152604080832080546001600160a01b0319169588169586179055602d825280832094835293905282902042905590517fff0456758201108de53c0ff04c69988d4678ff455b2ce6f733328cf85722c04c90612b12908590615c42565b60405180910390a2505050565b6060610cb660036147b2565b6017546001600160a01b03163314612b56576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b038116612b7d5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415612bde576040516001600160a01b0382169083156108fc029084906000818181858888f19350505050158015612bd8573d6000803e3d6000fd5b50612bf2565b612bf26001600160a01b0384168284614f9e565b604080516001600160a01b0385811682526020820185905283168183015290517f9a3055ded8c8b5f21bbf4946c5afab6e1fa8b3f057922658e5e1ade125fb0b1e9181900360600190a1505050565b6017546001600160a01b03163314612c6c576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166000908152601a602052604090205460ff1615612ca65760405163274e25dd60e11b815260040160405180910390fd5b6001600160a01b0381166000908152601a602052604090819020805460ff19166001179055517f8addc69f897ecca0e41d70ed4ff9d75a9148a615a0fbda8597e53aea2684302f90611205908390615c42565b6001600160a01b038381166000908152600160205260409020548491163314612d3557604051636efb4f4160e11b815260040160405180910390fd5b6001600160a01b038216612d5c5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03808516600090815260136020908152604080832093871683529290522054612d9f5760405163184c088160e21b815260040160405180910390fd5b6001600160a01b038085166000908152601260209081526040808320938716835292905220544211612de4576040516327cfdcb760e01b815260040160405180910390fd5b6001600160a01b03841660009081526007602052604090205460ff1615612e1e576040516362e6201d60e01b815260040160405180910390fd5b6001600160a01b0380851660008181526013602090815260408083209488168084529482528083208054908490559383526012825280832085845290915281205590612e6b908483614f9e565b826001600160a01b0316846001600160a01b0316866001600160a01b03167ffdb7893bf11f50c621e59cc7f1cf540e94295cb27ca869ec7ed7618ca792886284604051612eba91815260200190565b60405180910390a45050505050565b60026000541415612eec5760405162461bcd60e51b81526004016117be90615d4b565b600260009081553381526007602052604090205460ff1615612f21576040516362e6201d60e01b815260040160405180910390fd5b612f2c6015336147c6565b15612f4a5760405163d7229c4360e01b815260040160405180910390fd5b601f54612f579042615db1565b3360009081526011602090815260408083206001600160a01b03871680855292528083209390935591516370a0823160e01b81529091906370a0823190612fa2903090600401615c42565b60206040518083038186803b158015612fba57600080fd5b505afa158015612fce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff29190615bdf565b90506130096001600160a01b03841633308561506c565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190613037903090600401615c42565b60206040518083038186803b15801561304f57600080fd5b505afa158015613063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130879190615bdf565b6130919190615e4c565b336000908152601460209081526040808320805460ff19166001179055601082528083206001600160a01b03881684529091528120805492945084929091906130db908490615db1565b90915550506040518281526001600160a01b0384169033907fa7e66869262026842e8d81f5e6806cdc8d846e27c824e2e22f4fe51442771b349060200160405180910390a35050600160005550565b6020546131379042615db1565b3360008181526012602090815260408083206001600160a01b03881680855290835281842095909555928252600881528282209382529290925281208054839290613183908490615e4c565b90915550503360009081526013602090815260408083206001600160a01b0386168452909152812080548392906131bb908490615db1565b90915550506040518181526001600160a01b0383169033907f9aaab310d247ad45aef26bbdefc4ebf20c728fdb84c92b95b2b05d21826940de90602001611703565b6017546001600160a01b03163314613228576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b03811660009081526019602052604090205460ff16613261576040516336fe17e760e21b815260040160405180910390fd5b6001600160a01b03811660009081526019602052604090819020805460ff19169055517f3ed8cbce8cab40e59282f1743e2b607effa08b5cbe0111bb4721134f2f80d02590611205908390615c42565b6017546001600160a01b031633146132dc576040516354348f0360e01b815260040160405180910390fd5b601880546001600160a01b0319166001600160a01b0383161790556040517fe987aaedf9d279143bdf1eee16cf1d0feb47742867d81083df8d6cd0a5ac857f90611205908390615c42565b6001600160a01b03818116600090815260016020526040902054829116331461336357604051636efb4f4160e11b815260040160405180910390fd5b6001600160a01b03831660009081526007602052604090205460ff16806133a257506001600160a01b03821660009081526007602052604090205460ff165b156133c05760405163ad2fdf3b60e01b815260040160405180910390fd5b6001600160a01b038381166000908152602c60205260409020548116908316146133fd57604051630ced616b60e21b815260040160405180910390fd5b6001600160a01b038084166000908152602d602090815260408083209386168352929052205461342f90603c90615db1565b42101561344f576040516356248e9760e01b815260040160405180910390fd5b6134588361500e565b6134618261500e565b6001600160a01b0383166000908152600c602052604081206134829061511c565b1115613564576001600160a01b0383166000908152600c602052604081206134aa9082615126565b6001600160a01b03808616600090815260096020818152604080842085871680865290835281852054958a1685529282528084209284529190528120805493945091926134f8908490615db1565b90915550506001600160a01b0380851660008181526009602090815260408083209486168352938152838220829055918152600c9091522061353a9082615107565b506001600160a01b0383166000908152600c6020526040902061355d9082614ff9565b5050613461565b6001600160a01b0383166000908152600d602052604081206135859061511c565b1115613667576001600160a01b0383166000908152600d602052604081206135ad9082615126565b6001600160a01b03808616600090815260286020818152604080842085871680865290835281852054958a1685529282528084209284529190528120805493945091926135fb908490615db1565b90915550506001600160a01b038085166000908152602860209081526040808320858516845282528083208390559286168252600d90522061363d9082614ff9565b506001600160a01b0384166000908152600d602052604090206136609082615107565b5050613564565b6001600160a01b038084166000908152600b602052604080822054928516825281208054909190613699908490615db1565b90915550506001600160a01b038084166000908152600b60209081526040808320839055600a909152808220549285168252812080549091906136dd908490615db1565b90915550506001600160a01b0383166000908152600a602090815260408083208390556029909152812055613713601584615107565b506001600160a01b03808416600081815260016020908152604080832080546001600160a01b031990811690915560028352818420805482169055602d8352818420958816808552958352818420849055938352602c909152908190208054909216909155517f9b712b63e3fb1325fa042d3c238ce8144937875065900528ea1e4f3b00f379f290612b12908690615c42565b6017546001600160a01b031633146137d1576040516354348f0360e01b815260040160405180910390fd5b60238190556040518181527fbdcfd7b8482f31cff6a87c362d9e2e3887f4cdc2018c7c485d8e78a7b2fadb6990602001611205565b6017546001600160a01b03163314613831576040516354348f0360e01b815260040160405180910390fd5b61383c602682614ff9565b6138595760405163f25e6b9f60e01b815260040160405180910390fd5b806001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561389257600080fd5b505afa1580156138a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ca9190615939565b6001600160a01b038281166000908152600e60205260409081902080546001600160a01b0319169383169384179055601d54905163696a437b60e01b815291169163696a437b9161391e9190600401615c42565b60206040518083038186803b15801561393657600080fd5b505afa15801561394a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396e9190615b68565b6001600160a01b0382166000908152600f60205260409020805460ff191691151591909117905561399e81611210565b6001600160a01b0382166000908152602b60209081526040918290208351815492850151600690810b66ffffffffffffff908116600160381b026001600160701b03199095169290910b161791909117815591810151600190920191909155517fabfa8db4d238fa78bf4e15fcc91328dd35f3978f200e2857a56bb719732b7b0b90611205908390615c42565b6017546001600160a01b03163314613a56576040516354348f0360e01b815260040160405180910390fd5b601f8190556040518181527fd319ef78d2b690bb773fcccc2d096306bac7c9222dd0bb6b300f461e4a376b4390602001611205565b3360009081526019602052604090205460ff16613abb57604051637e57b1e160e01b815260040160405180910390fd5b6001600160a01b03841660009081526007602052604090205460ff16613af4576040516310cec38560e21b815260040160405180910390fd5b613b0084848484615132565b336001600160a01b0385167f10a73de7ab6e9023aa6e2bc23f7abf4dcef591487e7e55f44c00e34fe60d56db613b368486615db1565b60405190815260200160405180910390a350505050565b613b586015826147c6565b15613b7657604051630809740d60e01b815260040160405180910390fd5b6001600160a01b03811660009081526014602052604090205460ff1615613bb057604051632f3d320560e01b815260040160405180910390fd5b613bbb601582614ff9565b506001600160a01b03811660008181526001602052604080822080546001600160a01b03191633908117909155905190917fed3faef50715743626cd57de74281a2b17cdbfc11c0486feda541fb911e0293d91a350565b6017546001600160a01b03163314613c3d576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b038116613c645760405163d92e233d60e01b815260040160405180910390fd5b601c80546001600160a01b0319166001600160a01b0383161790556040517feb931b4b5a98d20a6b1e6693a7c59d8e337a06e2f1473bb776e19251db7ae25090611205908390615c42565b6017546001600160a01b03163314613cda576040516354348f0360e01b815260040160405180910390fd5b62015180811015613cfe57604051633f384aad60e21b815260040160405180910390fd5b60228190556040518181527f54aafa56429e22230b52f1495588ffc632277d74f3a85ec755e13ac50c1584d990602001611205565b60026000541415613d565760405162461bcd60e51b81526004016117be90615d4b565b600260009081556001600160a01b03858116825260016020526040909120548591163314613d9757604051636efb4f4160e11b815260040160405180910390fd5b6001600160a01b03808616600090815260256020908152604080832093881683529290522054613dc990603c90615db1565b4211613de857604051631e0b407560e01b815260040160405180910390fd5b6001600160a01b03808616600090815260096020908152604080832093881683529290522054831115613e2e5760405163024ae82d60e61b815260040160405180910390fd5b6001600160a01b03851660009081526007602052604090205460ff1615613e685760405163ad2fdf3b60e01b815260040160405180910390fd5b6001600160a01b03808616600090815260096020908152604080832093881683529290529081208054859290613e9f908490615e4c565b90915550613eb990506001600160a01b0385168385614f9e565b6001600160a01b03808616600090815260096020908152604080832093881683529290522054613f07576001600160a01b0385166000908152600c60205260409020613f059085615107565b505b816001600160a01b0316846001600160a01b0316866001600160a01b03167f53e982dd9ec088d634c74c98fbbc161f808b4b6469a26c657120b9a31cb34bfe86604051613f5691815260200190565b60405180910390a450506001600055505050565b3360008181526007602052604090205460ff1615613f9b5760405163ad2fdf3b60e01b815260040160405180910390fd5b6001600160a01b03831660009081526007602052604090205460ff1615613fd5576040516362e6201d60e01b815260040160405180910390fd5b613fe06015826147c6565b613ffc5760405162941a5760e11b815260040160405180910390fd5b6001600160a01b038082166000908152600960209081526040808320938816835292905220548211156140425760405163356680b760e01b815260040160405180910390fd5b6001600160a01b03808216600090815260096020908152604080832093881683529290529081208054849290614079908490615e4c565b9091555061409390506001600160a01b0385168484614f9e565b826001600160a01b0316816001600160a01b0316856001600160a01b0316600080516020615f56833981519152856140c9614e6d565b6040805192835260208301919091520160405180910390a450505050565b6017546001600160a01b03163314614112576040516354348f0360e01b815260040160405180910390fd5b60218190556040518181527f24d51b415694a791b1c77df7817c075ac82b83ce611bcd8627d2e66cf37aa3e790602001611205565b6017546001600160a01b03163314614172576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166141995760405163d92e233d60e01b815260040160405180910390fd5b601b80546001600160a01b0319166001600160a01b0383161790556040517f1d1a3e7caf0717056e48dc8aefa54d806c7af86324fece4e5d49f8e1f01f84bf90611205908390615c42565b6017546001600160a01b0316331461420f576040516354348f0360e01b815260040160405180910390fd5b6001600160a01b0381166000908152601a602052604090205460ff1661424857604051633ca0d42760e11b815260040160405180910390fd5b6001600160a01b0381166000908152601a602052604090819020805460ff19169055517f5e8bd21d0a98cb2caf33706e56139ff40ffbdca7ec5d9d412a0a2292496dc70e90611205908390615c42565b3360009081526019602052604090205460ff166142c857604051637e57b1e160e01b815260040160405180910390fd5b6001600160a01b03831660009081526007602052604090205460ff16614301576040516310cec38560e21b815260040160405180910390fd5b6001600160a01b0383166000908152600c6020526040902061432390836147c6565b61434057604051632eda7a1160e01b815260040160405180910390fd5b6001600160a01b038084166000908152600960209081526040808320938616835292905220548111156143855760405162919bed60e01b815260040160405180910390fd5b60175460405163a9059cbb60e01b81526001600160a01b038481169263a9059cbb926143b992909116908590600401615cb2565b602060405180830381600087803b1580156143d357600080fd5b505af1925050508015614403575060408051601f3d908101601f1916820190925261440091810190615b68565b60015b61440c5761440e565b505b6001600160a01b03808416600090815260096020908152604080832093861683529290529081208054839290614445908490615e4c565b90915550506001600160a01b03808416600090815260096020908152604080832093861683529290522054614498576001600160a01b0383166000908152600c602052604090206144969083615107565b505b336001600160a01b0316836001600160a01b03167f20262b97130b5cb8f80624eed2733df2b05db4a0789b4a3d0157e1d318333104848460405161277f929190615cb2565b336000908152601a602052604090205460ff1661450d57604051630942721960e31b815260040160405180910390fd5b6001600160a01b03811660009081526007602052604090205460ff1615614547576040516304ee891b60e11b815260040160405180910390fd5b6001600160a01b038116600081815260076020526040808220805460ff19166001179055513392917f070125a1c0f5202217aae14ec399abfaaa13c2fd98a91d43bd3a897dd4751e8091a350565b600061459f614e6d565b602e556145ad6003876147c6565b80156145de57506001600160a01b038087166000908152600860209081526040808320938916835292905220548411155b801561460257506001600160a01b0386166000908152600560205260409020548311155b801561463157506001600160a01b038616600090815260066020526040902054829061462e9042615e4c565b10155b15614675577f4851cad52e624c8f7a1d44c28a80db05988ba2451fc0db6b0ec338d8eca95afb602e5460405161466991815260200190565b60405180910390a15060015b95945050505050565b6017546001600160a01b031633146146a9576040516354348f0360e01b815260040160405180910390fd5b6146b46015836147c6565b6146d157604051636211d34960e01b815260040160405180910390fd5b6146da8261500e565b6001600160a01b0382166000908152600a602052604081208054839290614702908490615db1565b90915550506001600160a01b038216600081815260296020908152604080832054600a909252918290205491517f5abcf5031fdbd3badb9d1e09094208de329aee72730e87650f346584205d23d192614762928252602082015260400190565b60405180910390a25050565b60006022548261477e9190615eaa565b610dbb9083615e4c565b6000602254831015612637576022546147a18385615ddd565b6147ab9190615dc9565b9050610dbb565b606060006147bf83615288565b9392505050565b6001600160a01b038116600090815260018301602052604081205415156147bf565b6000610dbb826022546023546152e4565b6002600054141561481c5760405162461bcd60e51b81526004016117be90615d4b565b600260009081556001600160a01b0384168152600d6020526040902061484290836147c6565b61485e576040516241cfa560e21b815260040160405180910390fd5b6001600160a01b038084166000908152602860209081526040808320938616835292905220548111156148a45760405163435b562560e01b815260040160405180910390fd5b6148ad83615392565b60006148bc610dab8385614a07565b6001600160a01b0385166000908152600b602052604090205490915015614972576001600160a01b0384166000908152600b6020908152604080832054600a9092529091205461490d908390615ddd565b6149179190615dc9565b6001600160a01b0385166000908152600a60205260408120805490919061493f908490615e4c565b90915550506001600160a01b0384166000908152600b60205260408120805483929061496c908490615e4c565b90915550505b6001600160a01b038085166000908152602860209081526040808320938716835292905290812080548492906149a9908490615e4c565b90915550506001600160a01b038085166000908152602860209081526040808320938716835292905220546149fc576001600160a01b0384166000908152600d602052604090206149fa9084615107565b505b505060016000555050565b6001600160a01b0381166000908152602b602052604081206001015415610dbb576001600160a01b0382166000908152600f602052604081205460ff16614a79576001600160a01b0383166000908152602b6020526040902054614a7490600160381b900460060b615ebe565b614a9d565b6001600160a01b0383166000908152602b6020526040902054600160381b900460060b5b601d5460225460405163a0d2710760e01b81529293506001600160a01b039091169163a0d2710791614ad59188918691600401615d82565b60206040518083038186803b158015614aed57600080fd5b505afa158015614b01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca29190615bdf565b6000614b304261476e565b6001600160a01b03831660009081526029602052604090205410156115d157614b6060225442610bc69190615e4c565b6001600160a01b03831660009081526029602052604090205411614bd657614b8782615392565b6001600160a01b0382166000908152600b6020908152604080832054600a90925290912055614bb54261476e565b6001600160a01b038316600090815260296020526040902055506001919050565b6022546001600160a01b038316600090815260296020526040902054614bfc9042615e4c565b10614c5857614c0a82615392565b6001600160a01b0382166000908152600b6020908152604080832054600a83528184205560225460299092528220805491929091614c49908490615db1565b90915550600191506115d19050565b614c614261476e565b6001600160a01b0383166000908152602a602052604090205410156115d1576001600160a01b0382166000908152600b6020526040902054614ca283615392565b6001600160a01b0383166000908152600b6020908152604080832054600a909252909120548291614cd291615ddd565b614cdc9190615dc9565b6001600160a01b0384166000908152600a602052604090205550919050565b6001600160a01b038116600090815260296020526040902054614d4090614d229042615e4c565b6001600160a01b0383166000908152600b6020526040902054614788565b6001600160a01b0382166000908152600a602052604081208054909190614d68908490615db1565b90915550506001600160a01b03166000908152602960205260409020429055565b6001600160a01b0383166000908152600a6020526040902054811115614dc25760405163356680b760e01b815260040160405180910390fd5b6001600160a01b0383166000908152602a60209081526040808320429055600a90915281208054839290614df7908490615e4c565b90915550506001600160a01b038083166000908152600860209081526040808320601b5490941683529290529081208054839290614e36908490615db1565b90915550506001600160a01b03821660009081526005602052604081208054839290614e63908490615db1565b9091555050505050565b6000603f5a614e7d906040615ddd565b610cb69190615dc9565b6001600160a01b038216600090815260066020526040812054614ec0576001600160a01b03831660009081526006602052604090204290555b614ecb600384614ff9565b50506001600160a01b03808316600081815260106020908152604080832094861680845294825280832080549084905593835260088252808320948352939052918220805491928392614f1f908490615db1565b9091555050601b546001600160a01b0383811691161415610dbb57601b54604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b158015614f8057600080fd5b505af1158015614f94573d6000803e3d6000fd5b5050505092915050565b614ff48363a9059cbb60e01b8484604051602401614fbd929190615cb2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526153b7565b505050565b60006147bf836001600160a01b038416615489565b61501781614b25565b5061502181614cfb565b6001600160a01b0381166000908152600a6020908152604080832054600b9092529091205461505091906154d8565b6001600160a01b039091166000908152600a6020526040902055565b6040516001600160a01b03808516602483015283166044820152606481018290526150a49085906323b872dd60e01b90608401614fbd565b50505050565b6000808486602e546150bc9190615e4c565b6150c69190615db1565b9050670de0b6b3a7640000846127106150df8685615ddd565b6150e99190615dc9565b6150f39190615ddd565b6150fd9190615dc9565b9695505050505050565b60006147bf836001600160a01b0384166154ee565b6000610dbb825490565b60006147bf83836155e1565b601b546001600160a01b0384811691161461520a576017546001600160a01b038085169163a9059cbb91166151678486615db1565b6040518363ffffffff1660e01b8152600401615184929190615cb2565b602060405180830381600087803b15801561519e57600080fd5b505af19250505080156151ce575060408051601f3d908101601f191682019092526151cb91810190615b68565b60015b615208573d8080156151fc576040519150601f19603f3d011682016040523d82523d6000602084013e615201565b606091505b505061520a565b505b6001600160a01b03808516600090815260086020908152604080832093871683529290529081208054849290615241908490615e4c565b90915550506001600160a01b0380851660009081526013602090815260408083209387168352929052908120805483929061527d908490615e4c565b909155505050505050565b6060816000018054806020026020016040519081016040528092919081815260200182805480156152d857602002820191906000526020600020905b8154815260200190600101908083116152c4575b50505050509050919050565b60008080600019858709858702925082811083820303915050806000141561531e576000841161531357600080fd5b5082900490506147bf565b80841161532a57600080fd5b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b61539b8161560b565b6001600160a01b039091166000908152600b6020526040902055565b600061540c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166157ef9092919063ffffffff16565b805190915015614ff4578080602001905181019061542a9190615b68565b614ff45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016117be565b60008181526001830160205260408120546154d057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610dbb565b506000610dbb565b60008183106154e757816147bf565b5090919050565b600081815260018301602052604081205480156155d7576000615512600183615e4c565b855490915060009061552690600190615e4c565b905081811461558b57600086600001828154811061554657615546615f27565b906000526020600020015490508087600001848154811061556957615569615f27565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061559c5761559c615f11565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610dbb565b6000915050610dbb565b60008260000182815481106155f8576155f8615f27565b9060005260206000200154905092915050565b60006156164261476e565b601e546001600160a01b03166000908152602b6020526040902060010154146156ad57601e5461564e906001600160a01b0316611210565b601e546001600160a01b03166000908152602b60209081526040918290208351815492850151600690810b66ffffffffffffff908116600160381b026001600160701b03199095169290910b1617919091178155910151600191909101555b60005b6001600160a01b0383166000908152600d602052604090206156d19061511c565b811015612637576001600160a01b0383166000908152600d602052604081206156fa9083615126565b90506157076026826147c6565b156157dc576157154261476e565b6001600160a01b0382166000908152602b60205260409020600101541461579b5761573f81611210565b6001600160a01b0382166000908152602b60209081526040918290208351815492850151600690810b66ffffffffffffff908116600160381b026001600160701b03199095169290910b16179190911781559101516001909101555b6001600160a01b038085166000908152602860209081526040808320938516835292905220546157cf90610dab9083614a07565b6157d99084615db1565b92505b50806157e781615e8f565b9150506156b0565b6060610ca2848460008585843b6158485760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016117be565b600080866001600160a01b031685876040516158649190615c26565b60006040518083038185875af1925050503d80600081146158a1576040519150601f19603f3d011682016040523d82523d6000602084013e6158a6565b606091505b50915091506158b68282866158c1565b979650505050505050565b606083156158d05750816147bf565b8251156158e05782518084602001fd5b8160405162461bcd60e51b81526004016117be9190615d18565b805180151581146115d157600080fd5b8051600681900b81146115d157600080fd5b60006020828403121561592e57600080fd5b81356147bf81615f3d565b60006020828403121561594b57600080fd5b81516147bf81615f3d565b6000806040838503121561596957600080fd5b823561597481615f3d565b9150602083013561598481615f3d565b809150509250929050565b6000806000606084860312156159a457600080fd5b83356159af81615f3d565b925060208401356159bf81615f3d565b915060408401356159cf81615f3d565b809150509250925092565b6000806000606084860312156159ef57600080fd5b83356159fa81615f3d565b92506020840135615a0a81615f3d565b929592945050506040919091013590565b60008060008060808587031215615a3157600080fd5b8435615a3c81615f3d565b93506020850135615a4c81615f3d565b9250604085013591506060850135615a6381615f3d565b939692955090935050565b60008060008060808587031215615a8457600080fd5b8435615a8f81615f3d565b93506020850135615a9f81615f3d565b93969395505050506040820135916060013590565b600080600080600060a08688031215615acc57600080fd5b8535615ad781615f3d565b94506020860135615ae781615f3d565b94979496505050506040830135926060810135926080909101359150565b60008060408385031215615b1857600080fd5b8235615b2381615f3d565b946020939093013593505050565b600080600060608486031215615b4657600080fd5b8335615b5181615f3d565b92506020840135915060408401356159cf81615f3d565b600060208284031215615b7a57600080fd5b6147bf826158fa565b600080600060608486031215615b9857600080fd5b615ba18461590a565b9250615baf6020850161590a565b9150615bbd604085016158fa565b90509250925092565b600060208284031215615bd857600080fd5b5035919050565b600060208284031215615bf157600080fd5b5051919050565b600080600060608486031215615c0d57600080fd5b8351925060208401519150604084015190509250925092565b60008251615c38818460208701615e63565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b81811015615ca557845163ffffffff1683529383019391830191600101615c83565b5090979650505050505050565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015615d0c5783516001600160a01b031683529284019291840191600101615ce7565b50909695505050505050565b6020815260008251806020840152615d37816040850160208701615e63565b601f01601f19169190910160400192915050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b92835260069190910b6020830152604082015260600190565b9283526020830191909152604082015260600190565b60008219821115615dc457615dc4615ee5565b500190565b600082615dd857615dd8615efb565b500490565b6000816000190483118215151615615df757615df7615ee5565b500290565b60008160060b8360060b6000811281667fffffffffffff1901831281151615615e2757615e27615ee5565b81667fffffffffffff018313811615615e4257615e42615ee5565b5090039392505050565b600082821015615e5e57615e5e615ee5565b500390565b60005b83811015615e7e578181015183820152602001615e66565b838111156150a45750506000910152565b6000600019821415615ea357615ea3615ee5565b5060010190565b600082615eb957615eb9615efb565b500690565b60008160060b667fffffffffffff19811415615edc57615edc615ee5565b60000392915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0381168114615f5257600080fd5b5056fe46f2180879a7123a197cc3828c28955d70d661c70acbdc02450daf5f9a9c1cfaee3f0daba9837d1ab0597acf34328550e4832d02e24e467825e7c2dd318c3820a2646970667358221220a652922e4d7790b0f864618e6193f295e00a8e3132caf1f7755731c5f43e8adb64736f6c63430008070033

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

00000000000000000000000054054ea2db6edc336cb87966815fd66cc337f224000000000000000000000000d36ac9ff5562abb541f51345f340fb650547a6610000000000000000000000001ceb5cb57c4d4e2b2433641b95dd330a33185a44000000000000000000000000976b01c02c636dd5901444b941442fd70b86dcd500000000000000000000000011b7a6bc0259ed6cf9db8f499988f9ecc7167bf5

-----Decoded View---------------
Arg [0] : _governance (address): 0x54054EA2db6eDC336cB87966815FD66Cc337f224
Arg [1] : _keep3rHelper (address): 0xD36Ac9Ff5562abb541F51345f340FB650547a661
Arg [2] : _keep3rV1 (address): 0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44
Arg [3] : _keep3rV1Proxy (address): 0x976b01c02c636Dd5901444B941442FD70b86dcd5
Arg [4] : _kp3rWethPool (address): 0x11B7a6bc0259ed6Cf9DB8F499988F9eCc7167bf5

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000054054ea2db6edc336cb87966815fd66cc337f224
Arg [1] : 000000000000000000000000d36ac9ff5562abb541f51345f340fb650547a661
Arg [2] : 0000000000000000000000001ceb5cb57c4d4e2b2433641b95dd330a33185a44
Arg [3] : 000000000000000000000000976b01c02c636dd5901444b941442fd70b86dcd5
Arg [4] : 00000000000000000000000011b7a6bc0259ed6cf9db8f499988f9ecc7167bf5


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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