Skip to content

Commit 7ea6442

Browse files
fix: correct integer-shift price floor and odd-tick TVL bounds
v3/v4 raw price: move the 2**192 divisor outside the integer shift so fractional sqrtPriceX96 values are not truncated before the decimal scaling. (sqrtPriceX96**2 * 10**den1 >> 192) / 10**den0 floors too early for low-price tokens (e.g. 9.87e-6 returns 9e-6; 4.9e-7 returns zero and the reciprocal raises ZeroDivisionError). Change to (sqrtPriceX96**2 * 10**den1) / ((1 << 192) * 10**den0). get_tvl_in_pool: replace tick // 2 with tick / 2 for the sqrt-price boundary exponent. Integer floor-division produces wrong results for odd ticks (fee=100, tick_spacing=1): position [0,1) returns zero token0 instead of ~4.999625e13; [1,2) doubles; negative odd ticks also overcount. Floating-point tick / 2 recovers the correct bounds. Reported by Xamit Kadirbekov and Daniyal Kadirbekov (GERO numerical software assurance, https://www.gero.uz/research/). Relates to issue uniswap-python#269 (low-price floor, still open). Co-Authored-By: Bob <bob@superuserlabs.org>
1 parent bc8fdf4 commit 7ea6442

2 files changed

Lines changed: 11 additions & 8 deletions

File tree

‎uniswap/uniswap.py‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,9 @@ def _token_to_token_swap_input(
740740
else:
741741
func = self.router.functions.swapExactTokensForTokens
742742
weth_address = self.get_weth_address()
743-
if is_same_address(input_token, weth_address) or is_same_address(output_token, weth_address):
743+
if is_same_address(input_token, weth_address) or is_same_address(
744+
output_token, weth_address
745+
):
744746
path = [input_token, output_token]
745747
else:
746748
path = [input_token, weth_address, output_token]
@@ -1010,7 +1012,8 @@ def _token_to_token_swap_output(
10101012
weth = self.get_weth_address()
10111013
path = (
10121014
[input_token, output_token]
1013-
if is_same_address(input_token, weth) or is_same_address(output_token, weth)
1015+
if is_same_address(input_token, weth)
1016+
or is_same_address(output_token, weth)
10141017
else [input_token, weth, output_token]
10151018
)
10161019
return self._build_and_send_tx(
@@ -1372,8 +1375,8 @@ def get_tvl_in_pool(self, pool: Contract) -> Tuple[float, float]:
13721375
# source: https://stackoverflow.com/questions/71814845/how-to-calculate-uniswap-v3-pools-total-value-locked-tvl-on-chain
13731376
liquidityNet = tickData[1]
13741377
liquidity_total += liquidityNet
1375-
sqrtPriceLow = 1.0001 ** (tick // 2)
1376-
sqrtPriceHigh = 1.0001 ** ((tick + TICK_SPACING) // 2)
1378+
sqrtPriceLow = 1.0001 ** (tick / 2)
1379+
sqrtPriceHigh = 1.0001 ** ((tick + TICK_SPACING) / 2)
13771380
token0_liquidity += self.get_token0_in_pool(
13781381
liquidity_total, sqrtPrice, sqrtPriceLow, sqrtPriceHigh
13791382
)
@@ -1879,8 +1882,8 @@ def get_raw_price(
18791882
den0 = self.get_token(token_out).decimals
18801883
den1 = self.get_token(token_in).decimals
18811884
sqrtPriceX96 = pool_contract.functions.slot0().call()[0]
1882-
raw_price = (sqrtPriceX96 * sqrtPriceX96 * 10**den1 >> (96 * 2)) / (
1883-
10**den0
1885+
raw_price = (sqrtPriceX96 * sqrtPriceX96 * 10**den1) / (
1886+
(1 << 192) * 10**den0
18841887
)
18851888
if t1.lower() == token_in.lower():
18861889
raw_price = 1 / raw_price

‎uniswap/uniswap4.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,8 +1635,8 @@ def get_token_token_spot_price(
16351635
token0, token1, fee, tick_spacing, hooks
16361636
)["sqrtPriceX96"]
16371637

1638-
spot_price: float = (spot_price_x96 * spot_price_x96 * 10**den0 >> (96 * 2)) / (
1639-
10**den1
1638+
spot_price: float = (spot_price_x96 * spot_price_x96 * 10**den0) / (
1639+
(1 << 192) * 10**den1
16401640
)
16411641
if not zero_for_one:
16421642
spot_price = 1 / spot_price

0 commit comments

Comments
 (0)