better overflow protection

This commit is contained in:
JulesCrown 2024-07-18 16:50:23 +02:00
parent b243874f02
commit 84999fc90a

View file

@ -51,6 +51,8 @@ contract LiquidityManager {
// creating a security margin for attacks on liquidity
uint256 internal constant MIN_CAPITAL_INEFFICIENCY = 100; // 120 = 20%
uint256 internal constant MAX_CAPITAL_INEFFICIENCY = 200;
// used to double-check price with uni oracle
uint32 internal constant PRICE_STABILITY_INTERVAL = 300; // 5 minutes in seconds
// the address of the Uniswap V3 factory
address private immutable factory;
@ -330,6 +332,26 @@ contract LiquidityManager {
}
}
function _recordVolumeAndPrice(uint256 currentPrice, uint256 fee) internal {
// assuming FEE is 1%
uint256 volume = fee * 100;
uint256 volumeWeightedPrice = currentPrice * volume;
// Check for potential overflow. 10**70 is close to 2^256
if (cumulativeVolumeWeightedPrice > 10**70) {
uint256 zipFactor = 10**35;
uint256 desiredPrecision = 10**5;
while (zipFactor * desiredPrecision > cumulativeVolume) {
zipFactor /= desiredPrecision;
}
// Handle overflow: zip historic trade data
cumulativeVolumeWeightedPrice = cumulativeVolumeWeightedPrice / zipFactor;
// cumulativeVolume should be well higer than zipFactor
cumulativeVolume = cumulativeVolume / zipFactor;
}
cumulativeVolumeWeightedPrice += volumeWeightedPrice;
cumulativeVolume += volume;
}
function _scrape() internal {
uint256 fee0 = 0;
uint256 fee1 = 0;
@ -350,6 +372,7 @@ contract LiquidityManager {
fee0 += collected0 - amount0;
fee1 += collected1 - amount1;
if (i == uint256(Stage.ANCHOR)) {
// the historic archor position is only an approximation for the price
int24 tick = token0isWeth ? -1 * (position.tickLower + ANCHOR_SPACING): position.tickUpper - ANCHOR_SPACING;
currentPrice = tickToPrice(tick);
}
@ -361,17 +384,7 @@ contract LiquidityManager {
if (fee0 > 0) {
if (token0isWeth) {
IERC20(address(weth)).transfer(feeDestination, fee0);
uint256 volume = fee0 * 100;
uint256 volumeWeightedPrice = currentPrice * volume;
// Check for potential overflow
if (cumulativeVolumeWeightedPrice > type(uint256).max - volumeWeightedPrice) {
// Handle overflow: reset
cumulativeVolumeWeightedPrice = volumeWeightedPrice;
cumulativeVolume = volume;
} else {
cumulativeVolumeWeightedPrice += volumeWeightedPrice;
cumulativeVolume += volume;
}
_recordVolumeAndPrice(currentPrice, fee0);
} else {
IERC20(address(harb)).transfer(feeDestination, fee0);
}
@ -381,35 +394,27 @@ contract LiquidityManager {
IERC20(address(harb)).transfer(feeDestination, fee1);
} else {
IERC20(address(weth)).transfer(feeDestination, fee1);
uint256 volume = fee1 * 100;
uint256 volumeWeightedPrice = currentPrice * volume;
// Check for potential overflow
if (cumulativeVolumeWeightedPrice > type(uint256).max - volumeWeightedPrice) {
// Handle overflow: reset
cumulativeVolumeWeightedPrice = volumeWeightedPrice;
cumulativeVolume = volume;
} else {
cumulativeVolumeWeightedPrice += volumeWeightedPrice;
cumulativeVolume += volume;
}
_recordVolumeAndPrice(currentPrice, fee1);
}
}
}
function _isPriceStable(int24 currentTick) internal view returns (bool) {
uint32 timeInterval = 300; // 5 minutes in seconds
uint32[] memory secondsAgo = new uint32[](2);
secondsAgo[0] = timeInterval; // 5 minutes ago
secondsAgo[0] = PRICE_STABILITY_INTERVAL; // 5 minutes ago
secondsAgo[1] = 0; // current block timestamp
int56 tickCumulativeDiff;
int24 averageTick;
try pool.observe(secondsAgo) returns (int56[] memory tickCumulatives, uint160[] memory) {
tickCumulativeDiff = tickCumulatives[1] - tickCumulatives[0];
averageTick = int24(tickCumulativeDiff / int56(int32(timeInterval)));
averageTick = int24(tickCumulativeDiff / int56(int32(PRICE_STABILITY_INTERVAL)));
} catch {
// TODO:
return false;
// try with a higher timeframe
secondsAgo[0] = PRICE_STABILITY_INTERVAL * 200;
(int56[] memory tickCumulatives, ) = pool.observe(secondsAgo);
tickCumulativeDiff = tickCumulatives[1] - tickCumulatives[0];
averageTick = int24(tickCumulativeDiff / int56(int32(PRICE_STABILITY_INTERVAL)));
}
return (currentTick >= averageTick - MAX_TICK_DEVIATION && currentTick <= averageTick + MAX_TICK_DEVIATION);