Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: casting
Browse files Browse the repository at this point in the history
xenide committed Mar 5, 2024
1 parent 1680839 commit 36e1709
Showing 7 changed files with 28 additions and 30 deletions.
23 changes: 11 additions & 12 deletions src/ReservoirPair.sol
Original file line number Diff line number Diff line change
@@ -519,7 +519,7 @@ abstract contract ReservoirPair is IAssetManagedPair, ReservoirERC20 {
function _calcClampedPrice(uint256 aCurrRawPrice, uint256 aPrevClampedPrice, uint256 aTimeElapsed)
internal
virtual
returns (uint256 rClampedPrice, int112 rClampedLogPrice)
returns (uint256 rClampedPrice, int256 rClampedLogPrice)
{
// call to `percentDelta` will revert if the difference between aCurrRawPrice and aPrevClampedPrice is
// greater than uint196 (1e59). It is extremely unlikely that one trade can change the price by 1e59
@@ -536,7 +536,7 @@ abstract contract ReservoirPair is IAssetManagedPair, ReservoirERC20 {
assert(aPrevClampedPrice > aCurrRawPrice);
rClampedPrice = aPrevClampedPrice.fullMulDiv(1e18 - maxChangeRate * aTimeElapsed, 1e18);
}
rClampedLogPrice = int112(LogCompression.toLowResLog(rClampedPrice));
rClampedLogPrice = LogCompression.toLowResLog(rClampedPrice);
}
}

@@ -548,28 +548,27 @@ abstract contract ReservoirPair is IAssetManagedPair, ReservoirERC20 {
) internal {
Observation storage previous = _observations[_slot0.index];

(, int112 logInstantClampedPrice) = _calcClampedPrice(
(, int256 logInstantClampedPrice) = _calcClampedPrice(
aInstantRawPrice, LogCompression.fromLowResLog(previous.logInstantClampedPrice), aTimeElapsed
);

// overflow is desired here as the consumer of the oracle will be reading the difference in those accumulated log values
// when the index overflows it will overwrite the oldest observation to form a loop
unchecked {
int112 logAccRawPrice =
previous.logAccRawPrice + previous.logInstantRawPrice * int112(int256(uint256(aTimeElapsed)));
int56 logAccClampedPrice =
previous.logAccClampedPrice + previous.logInstantClampedPrice * int56(int256(uint256(aTimeElapsed)));
int88 logAccRawPrice =
previous.logAccRawPrice + previous.logInstantRawPrice * int88(int256(uint256(aTimeElapsed)));
int88 logAccClampedPrice =
previous.logAccClampedPrice + previous.logInstantClampedPrice * int88(int256(uint256(aTimeElapsed)));
_slot0.index += 1;
_observations[_slot0.index] = Observation(
// TODO: prove that these values are guaranteed <=int56 to remove these safe casts
SafeCast.toInt56(aLogInstantRawPrice),
SafeCast.toInt56(logInstantClampedPrice),
SafeCast.toInt56(logAccRawPrice),
int24(aLogInstantRawPrice),
int24(logInstantClampedPrice),
logAccRawPrice,
logAccClampedPrice,
aCurrentTimestamp
);
}
}

function _calcInstantRawPrice(uint256 aBalance0, uint256 aBalance1) internal virtual returns (uint256, int112);
function _calcInstantRawPrice(uint256 aBalance0, uint256 aBalance1) internal virtual returns (uint256, int256);
}
2 changes: 1 addition & 1 deletion src/curve/constant-product/ConstantProductPair.sol
Original file line number Diff line number Diff line change
@@ -225,7 +225,7 @@ contract ConstantProductPair is ReservoirPair {
ORACLE METHODS
//////////////////////////////////////////////////////////////////////////*/

function _calcInstantRawPrice(uint256 aBalance0, uint256 aBalance1) internal override returns (uint256, int112) {
function _calcInstantRawPrice(uint256 aBalance0, uint256 aBalance1) internal override returns (uint256, int256) {
return ConstantProductOracleMath.calcLogPrice(
aBalance0 * token0PrecisionMultiplier(), aBalance1 * token1PrecisionMultiplier()
);
2 changes: 1 addition & 1 deletion src/curve/stable/StablePair.sol
Original file line number Diff line number Diff line change
@@ -279,7 +279,7 @@ contract StablePair is ReservoirPair {
ORACLE METHODS
//////////////////////////////////////////////////////////////////////////*/

function _calcInstantRawPrice(uint256 aBalance0, uint256 aBalance1) internal override returns (uint256, int112) {
function _calcInstantRawPrice(uint256 aBalance0, uint256 aBalance1) internal override returns (uint256, int256) {
return StableOracleMath.calcLogPrice(
_getCurrentAPrecise(), aBalance0 * token0PrecisionMultiplier(), aBalance1 * token1PrecisionMultiplier()
);
7 changes: 3 additions & 4 deletions src/libraries/ConstantProductOracleMath.sol
Original file line number Diff line number Diff line change
@@ -26,17 +26,16 @@ library ConstantProductOracleMath {
* @param reserve0 normalized to 18 decimals, and should never be 0 as checked by _updateAndUnlock().
* @param reserve1 normalized to 18 decimals, and should never be 0 as checked by _updateAndUnlock().
* @return spotPrice price of token1/token0, 18 decimals fixed point number. Minimum price is 1e-18 (1 wei), as we do not round to zero.
* @return logSpotPrice natural log of the spot price, 4 decimal fixed point number
* @return logSpotPrice natural log of the spot price, 4 decimal fixed point number. Min value is 1
*/
function calcLogPrice(uint256 reserve0, uint256 reserve1)
internal
pure
returns (uint256 spotPrice, int112 logSpotPrice)
returns (uint256 spotPrice, int256 logSpotPrice)
{
// Scaled by 1e18, minimum will be 1 wei as we divUp.
spotPrice = reserve1.divWadUp(reserve0);

int256 rawResult = LogCompression.toLowResLog(spotPrice);
logSpotPrice = int112(rawResult);
logSpotPrice = LogCompression.toLowResLog(spotPrice);
}
}
5 changes: 2 additions & 3 deletions src/libraries/StableOracleMath.sol
Original file line number Diff line number Diff line change
@@ -18,12 +18,11 @@ library StableOracleMath {
function calcLogPrice(uint256 amplificationParameter, uint256 reserve0, uint256 reserve1)
internal
pure
returns (uint256 spotPrice, int112 logSpotPrice)
returns (uint256 spotPrice, int256 logSpotPrice)
{
spotPrice = calcSpotPrice(amplificationParameter, reserve0, reserve1);

int256 rawLogSpotPrice = LogCompression.toLowResLog(spotPrice);
logSpotPrice = int112(rawLogSpotPrice);
logSpotPrice = LogCompression.toLowResLog(spotPrice);
}

/// @notice Calculates the spot price of token1 in token0
17 changes: 9 additions & 8 deletions src/structs/Observation.sol
Original file line number Diff line number Diff line change
@@ -2,18 +2,19 @@
pragma solidity ^0.8.0;

struct Observation {
// natural log (ln) of the raw instant price
int56 logInstantRawPrice;
// natural log (ln) of the raw instant price. Fits into int24 as the max value is 1353060
// See `LogCompressionTest` for more info
int24 logInstantRawPrice;
// natural log (ln) of the clamped instant price
int56 logInstantClampedPrice;
int24 logInstantClampedPrice;

// natural log (ln) of the raw accumulated price (token1/token0)
int56 logAccRawPrice;
// in the case of maximum price supported by the oracle (~2.87e56 == e ** 135.3060)
// (1353060) 21 bits multiplied by 32 bits of the timestamp gives 53 bits
// which fits into int88
int88 logAccRawPrice;
// natural log (ln) of the clamped accumulated price (token1/token0)
// in the case of maximum price supported by the oracle (~2.87e56 == e ** 130.0000)
// (1300000) 21 bits multiplied by 32 bits of the timestamp gives 53 bits
// which fits into int56
int56 logAccClampedPrice;
int88 logAccClampedPrice;

// overflows every 136 years, in the year 2106
uint32 timestamp;
2 changes: 1 addition & 1 deletion test/unit/libraries/ConstantProductMath.t.sol
Original file line number Diff line number Diff line change
@@ -71,7 +71,7 @@ contract ConstantProductMathTest is BaseTest {
uint256 lReserve0 = bound(aReserve1, lReserve1 * 1e18, type(uint104).max);

// act
(, int112 lLogPrice) = ConstantProductOracleMath.calcLogPrice(lReserve0, lReserve1);
(, int256 lLogPrice) = ConstantProductOracleMath.calcLogPrice(lReserve0, lReserve1);

// assert
assertEq(lLogPrice, LogCompression.toLowResLog(1));

0 comments on commit 36e1709

Please sign in to comment.