// SPDX-License-Identifier: MIT
/*
Coded for The Keep3r Network with ♥ by
██████╗░███████╗███████╗██╗ ░██╗░░░░░░░██╗░█████╗░███╗░░██╗██████╗░███████╗██████╗░██╗░░░░░░█████╗░███╗░░██╗██████╗░
██╔══██╗██╔════╝██╔════╝██║ ░██║░░██╗░░██║██╔══██╗████╗░██║██╔══██╗██╔════╝██╔══██╗██║░░░░░██╔══██╗████╗░██║██╔══██╗
██║░░██║█████╗░░█████╗░░██║ ░╚██╗████╗██╔╝██║░░██║██╔██╗██║██║░░██║█████╗░░██████╔╝██║░░░░░███████║██╔██╗██║██║░░██║
██║░░██║██╔══╝░░██╔══╝░░██║ ░░████╔═████║░██║░░██║██║╚████║██║░░██║██╔══╝░░██╔══██╗██║░░░░░██╔══██║██║╚████║██║░░██║
██████╔╝███████╗██║░░░░░██║ ░░╚██╔╝░╚██╔╝░╚█████╔╝██║░╚███║██████╔╝███████╗██║░░██║███████╗██║░░██║██║░╚███║██████╔╝
╚═════╝░╚══════╝╚═╝░░░░░╚═╝ ░░░╚═╝░░░╚═╝░░░╚════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝╚═╝░░╚══╝╚═════╝░
https://defi.sucks
*/
pragma solidity >=0.8.7 <0.9.0;
import './libraries/FullMath.sol';
import './libraries/TickMath.sol';
import '../interfaces/IKeep3r.sol';
import '../interfaces/external/IKeep3rV1.sol';
import '../interfaces/IKeep3rHelper.sol';
import '@openzeppelin/contracts/utils/math/Math.sol';
import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol';
contract Keep3rHelper is IKeep3rHelper {
address public immutable keep3rV2;
constructor(address _keep3rV2) {
keep3rV2 = _keep3rV2;
}
/// @inheritdoc IKeep3rHelper
address public constant override KP3R = 0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44;
/// @inheritdoc IKeep3rHelper
address public constant override KP3R_WETH_POOL = 0x11B7a6bc0259ed6Cf9DB8F499988F9eCc7167bf5;
/// @inheritdoc IKeep3rHelper
uint256 public constant override MIN = 11_000;
/// @inheritdoc IKeep3rHelper
uint256 public constant override MAX = 12_000;
/// @inheritdoc IKeep3rHelper
uint256 public constant override BOOST_BASE = 10_000;
/// @inheritdoc IKeep3rHelper
uint256 public constant override TARGETBOND = 200 ether;
/// @inheritdoc IKeep3rHelper
function quote(uint256 _eth) public view override returns (uint256 _amountOut) {
bool _isKP3RToken0 = isKP3RToken0(KP3R_WETH_POOL);
int56 _tickDifference = IKeep3r(keep3rV2).observeLiquidity(KP3R_WETH_POOL).difference;
_tickDifference = _isKP3RToken0 ? _tickDifference : -_tickDifference;
uint256 _tickInterval = IKeep3r(keep3rV2).rewardPeriodTime();
_amountOut = getQuoteAtTick(uint128(_eth), _tickDifference, _tickInterval);
}
/// @inheritdoc IKeep3rHelper
function bonds(address _keeper) public view override returns (uint256 _amountBonded) {
return IKeep3r(keep3rV2).bonds(_keeper, KP3R);
}
/// @inheritdoc IKeep3rHelper
function getRewardAmountFor(address _keeper, uint256 _gasUsed) public view override returns (uint256 _kp3r) {
uint256 _boost = getRewardBoostFor(bonds(_keeper));
_kp3r = quote((_gasUsed * _boost) / BOOST_BASE);
}
/// @inheritdoc IKeep3rHelper
function getRewardAmount(uint256 _gasUsed) external view override returns (uint256 _amount) {
// solhint-disable-next-line avoid-tx-origin
return getRewardAmountFor(tx.origin, _gasUsed);
}
/// @inheritdoc IKeep3rHelper
function getRewardBoostFor(uint256 _bonds) public view override returns (uint256 _rewardBoost) {
_bonds = Math.min(_bonds, TARGETBOND);
uint256 _cap = Math.max(MIN, MIN + ((MAX - MIN) * _bonds) / TARGETBOND);
_rewardBoost = _cap * _getBasefee();
}
/// @inheritdoc IKeep3rHelper
function getPoolTokens(address _pool) public view override returns (address _token0, address _token1) {
return (IUniswapV3Pool(_pool).token0(), IUniswapV3Pool(_pool).token1());
}
/// @inheritdoc IKeep3rHelper
function isKP3RToken0(address _pool) public view override returns (bool _isKP3RToken0) {
address _token0;
address _token1;
(_token0, _token1) = getPoolTokens(_pool);
if (_token0 == KP3R) {
return true;
} else if (_token1 != KP3R) {
revert LiquidityPairInvalid();
}
}
/// @inheritdoc IKeep3rHelper
function observe(address _pool, uint32[] memory _secondsAgo)
public
view
override
returns (
int56 _tickCumulative1,
int56 _tickCumulative2,
bool _success
)
{
try IUniswapV3Pool(_pool).observe(_secondsAgo) returns (int56[] memory _uniswapResponse, uint160[] memory) {
_tickCumulative1 = _uniswapResponse[0];
if (_uniswapResponse.length > 1) {
_tickCumulative2 = _uniswapResponse[1];
}
_success = true;
} catch (bytes memory) {}
}
/// @inheritdoc IKeep3rHelper
function getKP3RsAtTick(
uint256 _liquidityAmount,
int56 _tickDifference,
uint256 _timeInterval
) public pure override returns (uint256 _kp3rAmount) {
uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(int24(_tickDifference / int256(_timeInterval)));
_kp3rAmount = FullMath.mulDiv(1 << 96, _liquidityAmount, sqrtRatioX96);
}
/// @inheritdoc IKeep3rHelper
function getQuoteAtTick(
uint128 _baseAmount,
int56 _tickDifference,
uint256 _timeInterval
) public pure override returns (uint256 _quoteAmount) {
uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(int24(_tickDifference / int256(_timeInterval)));
if (sqrtRatioX96 <= type(uint128).max) {
uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96;
_quoteAmount = FullMath.mulDiv(1 << 192, _baseAmount, ratioX192);
} else {
uint256 ratioX128 = FullMath.mulDiv(sqrtRatioX96, sqrtRatioX96, 1 << 64);
_quoteAmount = FullMath.mulDiv(1 << 128, _baseAmount, ratioX128);
}
}
/// @notice Gets the block's base fee
/// @return _baseFee The block's basefee
function _getBasefee() internal view virtual returns (uint256 _baseFee) {
return block.basefee;
}
}
|