From 1936fe73556aadf847629039d7bc76748172f609 Mon Sep 17 00:00:00 2001 From: Seth Date: Wed, 5 Jun 2024 23:03:40 -0400 Subject: [PATCH] chore: add uniswap v2 and v3 pair reserve snapshot compute methodology --- .../uniswap-dashboard/data-points.md | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/docs/build-with-powerloom/use-cases/existing-implementations/uniswap-dashboard/data-points.md b/docs/build-with-powerloom/use-cases/existing-implementations/uniswap-dashboard/data-points.md index 0623f8f..7a6a26d 100644 --- a/docs/build-with-powerloom/use-cases/existing-implementations/uniswap-dashboard/data-points.md +++ b/docs/build-with-powerloom/use-cases/existing-implementations/uniswap-dashboard/data-points.md @@ -27,6 +27,47 @@ Liquidity reserves of each pair per Epoch. The reserves snapshot looks something https://github.com/PowerLoom/snapshotter-computes/blob/6fb98b1bbc22be8b5aba8bdc860004d35786f4df/utils/models/message_models.py#L20-L32 ``` +Significant differences between the V2 and V3 implementations can be found in the generation of this base snapshot and are outlined below: + +#### V2 Reserves Snapshot Caclulations + +The token reserve amounts for a UniswapV2 pair are retrieved from the [getReserves()](https://github.com/Uniswap/v2-core/blob/ee547b17853e71ed4e0101ccfd52e70d5acded58/contracts/UniswapV2Pair.sol#L38) function that is available in the `UniswapV2Pair` contract. These amounts are converted from their native integer format into a normalized decimal format and are then used to populate the snapshot's `token0Reserves` and `token1Reserves` fields. This calculation can be seen in the UniswapV2 compute module here: + +```python reference +https://github.com/PowerLoom/snapshotter-computes/blob/6fb98b1bbc22be8b5aba8bdc860004d35786f4df/utils/core.py#L103-L130 +``` + +The price of a token in a UniswapV2 pair can be derived using the ratio of the pair's token reserves, or by utilizing one of the pricing functions available in the `UniswapV2Library` contract such as [getAmountsOut()](https://github.com/Uniswap/v2-periphery/blob/0335e8f7e1bd1e8d8329fd300aea2ef2f36dd19f/contracts/libraries/UniswapV2Library.sol#L62-L70). See the [UniswapV2 Pricing](https://docs.uniswap.org/contracts/v2/concepts/advanced-topics/pricing) documentation for additional information. The snapshot's `token0Prices` and `token1Prices` fields are calculated by first deriving each token's price in terms of ETH (or the source chain's equivalent gas token), and then converting the resulting ETH price to USD terms. + +For each token, the compute attempts to find a UniswapV2 pair consisting of the given token and wrapped ETH (WETH). If the token's WETH pair exists, its ETH price is derived using the ratio of the pair's token reserves. If the token's WETH pair does not exist, an additional pair consisting of the given token and a whitelisted token is used to derive an intermediary price before converting it back in terms of ETH. This calculation can be seen in the [Pricing Utils](https://github.com/PowerLoom/snapshotter-computes/blob/1abcf639d00a2fed87f01fcf0332cfb090257272/utils/pricing.py#L259-L318) of the UniswapV2 compute module. + +The ETH price in terms of USD is calculated in Pooler's [Snapshot Utils](https://github.com/PowerLoom/pooler/blob/db969eb3956d77cbca36daaeb96fce70314a9b63/snapshotter/utils/snapshot_utils.py#L37-L184), and it is used to convert each token's ETH price to USD in the [Pricing Utils](https://github.com/PowerLoom/snapshotter-computes/blob/1abcf639d00a2fed87f01fcf0332cfb090257272/utils/pricing.py#L320-L331) of the UniswapV2 compute module. The results are used to populate the snapshot's `token0Prices` and `token1Prices` fields. + +The snapshot's `token0ReservesUSD` and `token1ReservesUSD` fields are calculated by applying the `token0Prices` and `token1Prices` to the `token0Reserves` and `token1Reserves` values respectively. This calculation can be seen in the [Core Utils](https://github.com/PowerLoom/snapshotter-computes/blob/1abcf639d00a2fed87f01fcf0332cfb090257272/utils/core.py#L132-L133) of the UniswapV2 compute module. + +#### V3 Reserves Snapshot Caclulations + +:::tip +The following section contains references to advanced concepts specific to the UniswapV3 Protocol. It is recommended that you read the [UniswapV3 Concepts](https://docs.uniswap.org/concepts/protocol/concentrated-liquidity) documentation as well as the [UniswapV3 Math Primer](https://blog.uniswap.org/uniswap-v3-math-primer) before continuing if you are unfamilar with the inner workings of the protocol. +::: + +Unlike the `UniswapV2Pair` contract, the `getReserves()` function is not available in the `UniswapV3Pool` contract, so the token reserve amounts cannot be retrieved directly from the chain and must be calculated manually. The calculation is computationally expensive, as it involves iterating over each available tick on the pool's price curve to sum the liquidity available at each tick. In order to reduce resource usage and limit the number of RPC requests, Powerloom's UniswapV3 dashboard implementation splits the computation of the `UniswapPairTotalReservesSnapshot` into two phases: + +1. An initial manual calculation of the token reserves for each pool using the `calculate_reserves()` function found in the [Total Value Locked Utils](https://github.com/PowerLoom/snapshotter-computes/blob/9241e32155107949ccf4dbc4214ef29a91996b7f/total_value_locked.py#L158-L182) of the UniswapV3 compute module. +2. Incremental adjustments to the initially calculated reserve values based on `Mint` and `Burn` events for each token in the pool. This calculation can be seen in the [Core Utils](https://github.com/PowerLoom/snapshotter-computes/blob/9241e32155107949ccf4dbc4214ef29a91996b7f/utils/core.py#L131-L168) of the UniswapV3 compute module. + +The resulting reserve values are used to populate the snapshot's `token0Reserves` and `token1Reserves` fields. + +The price of a token in a UniswapV3 pool can be calculated from the `sqrtPriceX96` value returned from a `UniswapV3Pool` contract's [slot0()](https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Pool.sol#L74) function. This value is returned in a format known as Q Notation. For additional information on Q notation and price calculation in UniswapV3, see the [UniswapV3 Math Primer](https://blog.uniswap.org/uniswap-v3-math-primer). + +The snapshot's `token0Prices` and `token1Prices` are computed following a similar process to the UniswapV2 calculation, however, instead of the using the ratio of the the token reserves or a pricing function, the prices are derived from each pool's `sqrtPriceX96`. This calculation can be seen here: + +```python reference +https://github.com/PowerLoom/pooler/blob/bf68b35eba32255e25d7b6701b0e5609fef86655/snapshotter/utils/snapshot_utils.py#L40-L49 +``` + +The snapshot's `token0ReservesUSD` and `token1ReservesUSD` fields are calculated by applying the `token0Prices` and `token1Prices` to the `token0Reserves` and `token1Reserves` values respectively. This calculation can be seen in the [Core Utils](https://github.com/PowerLoom/snapshotter-computes/blob/9241e32155107949ccf4dbc4214ef29a91996b7f/utils/core.py#L173-L176) of the UniswapV3 compute module. + ### 2. Trade Volume Snapshot Trade volume of each pair per Epoch. The trade volume snapshot looks something like this: