Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x1201291d53a29570fc7406771134ee273eaec6ab1906e90dcbdcd6448c854219 | Bond | (pending) | 2 days ago | IN | 0 ETH | (Pending) | |||
Bond | 20411404 | 22 hrs ago | IN | 0 ETH | 0.00036228 | ||||
Unbond | 20411217 | 23 hrs ago | IN | 0 ETH | 0.00022973 | ||||
Withdraw | 20411213 | 23 hrs ago | IN | 0 ETH | 0.00030823 | ||||
Unbond | 20396256 | 3 days ago | IN | 0 ETH | 0.00012778 | ||||
Withdraw | 20396254 | 3 days ago | IN | 0 ETH | 0.00014713 | ||||
Withdraw | 20354462 | 8 days ago | IN | 0 ETH | 0.00018274 | ||||
Unbond | 20297840 | 16 days ago | IN | 0 ETH | 0.00017284 | ||||
Withdraw | 20297835 | 16 days ago | IN | 0 ETH | 0.00022058 | ||||
Unbond | 20289020 | 18 days ago | IN | 0 ETH | 0.00037637 | ||||
Withdraw | 20289018 | 18 days ago | IN | 0 ETH | 0.00039089 | ||||
Unbond | 20252234 | 23 days ago | IN | 0 ETH | 0.00011816 | ||||
Activate | 20252226 | 23 days ago | IN | 0 ETH | 0.0002163 | ||||
Add Job | 20238656 | 25 days ago | IN | 0 ETH | 0.00179135 | ||||
Migrate Job | 20238465 | 25 days ago | IN | 0 ETH | 0.00095468 | ||||
Add Job | 20238454 | 25 days ago | IN | 0 ETH | 0.00125531 | ||||
Activate | 20238352 | 25 days ago | IN | 0 ETH | 0.00181226 | ||||
Bond | 20235075 | 25 days ago | IN | 0 ETH | 0.00057265 | ||||
Activate | 20234747 | 25 days ago | IN | 0 ETH | 0.00143787 | ||||
Bond | 20230646 | 26 days ago | IN | 0 ETH | 0.00033147 | ||||
Bond | 20213013 | 28 days ago | IN | 0 ETH | 0.00081727 | ||||
Bond | 20212583 | 28 days ago | IN | 0 ETH | 0.00186095 | ||||
Unbond | 20188578 | 32 days ago | IN | 0 ETH | 0.00024859 | ||||
Withdraw | 20188574 | 32 days ago | IN | 0 ETH | 0.00026763 | ||||
Unbond | 20183630 | 32 days ago | IN | 0 ETH | 0.00102706 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Keep3r
Compiler Version
v0.8.7+commit.e28d00a7
Optimization Enabled:
Yes with 33 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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() {} }
// 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 {}
// SPDX-License-Identifier: MIT pragma solidity >=0.8.4 <0.9.0; import './Keep3rKeeperDisputable.sol'; abstract contract Keep3rKeepers is Keep3rKeeperDisputable {}
// 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(); } }
// 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(); _; } }
// 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); } }
// 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); } }
// 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); } }
// 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; } }
// 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); } }
// 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); } }
// 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]); } }
// 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); } }
// 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(); _; } }
// 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 { }
// 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; } }
// 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); }
// 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"); } } }
// 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); } }
// 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; } }
// 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(); }
// 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); }
// 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; }
// 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(); }
// 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; }
// 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(); _; } }
// 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; }
// 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); } } } }
// 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); }
// 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++; } } } }
// 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); }
// 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; }
// 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); } }
// 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; } }
// 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); } } }
// 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; }
// 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 { }
// 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; }
// 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; }
{ "optimizer": { "enabled": true, "runs": 33 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
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
Loading...
Loading
Loading...
Loading
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.