{"id":19096802,"url":"https://github.com/makerdao/univ3-lp-oracle","last_synced_at":"2025-04-18T16:31:10.608Z","repository":{"id":39373506,"uuid":"382088232","full_name":"makerdao/univ3-lp-oracle","owner":"makerdao","description":null,"archived":false,"fork":false,"pushed_at":"2022-09-29T12:38:03.000Z","size":57,"stargazers_count":28,"open_issues_count":3,"forks_count":8,"subscribers_count":10,"default_branch":"master","last_synced_at":"2023-04-05T23:40:54.515Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Solidity","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/makerdao.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-07-01T16:04:55.000Z","updated_at":"2022-08-28T03:47:24.000Z","dependencies_parsed_at":"2023-01-17T21:31:08.162Z","dependency_job_id":null,"html_url":"https://github.com/makerdao/univ3-lp-oracle","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Funiv3-lp-oracle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Funiv3-lp-oracle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Funiv3-lp-oracle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makerdao%2Funiv3-lp-oracle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/makerdao","download_url":"https://codeload.github.com/makerdao/univ3-lp-oracle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223783307,"owners_count":17201901,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T03:37:50.325Z","updated_at":"2024-11-09T03:37:50.804Z","avatar_url":"https://github.com/makerdao.png","language":"Solidity","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Uniswap V3 LP Oracles\n\nContains vendor-specific implementations for Uniswap V3 oracles. The specific functions being called to determine underlying balances will vary between LP implementations, but the underlying logic should be roughly equivalent between all vendors.\n\n## General Price Calculation\n\nWe derive the sqrtPriceX96 via Maker's own oracles to prevent price manipulation in the pool:\n\n```\nDefine:\n\np0 = price of token0 in USD\np1 = price of token1 in USD\nUNITS_0 = decimals of token0\nUNITS_1 = decimals of token1\n\ntoken1/token0 = (p0 / 10^UNITS_0) / (p1 / 10^UNITS_1)               [Conversion from Maker's price ratio into Uniswap's format]\n              = (p0 * 10^UNITS_1) / (p1 * 10^UNITS_0)\n\nsqrtPriceX96 = sqrt(token1/token0) * 2^96                           [From Uniswap's definition]\n             = sqrt((p0 * 10^UNITS_1) / (p1 * 10^UNITS_0)) * 2^96\n             = sqrt((p0 * 10^UNITS_1) / (p1 * 10^UNITS_0)) * 2^48 * 2^48\n             = sqrt((p0 * 10^UNITS_1 * 2^96) / (p1 * 10^UNITS_0)) * 2^48\n```\n\nOnce we have the `sqrtPriceX96` we can use that to compute the fair reserves for each token. This part may be slightly subjective depending on the implementation, but we expect most tokens to provide something like `getUnderlyingBalancesAtPrice(uint160 sqrtPriceX96)` which will forward our oracle-calculated `sqrtPriceX96` to the Uniswap-provided [`LiquidityAmounts.getAmountsForLiquidity(...)`](https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/libraries/LiquidityAmounts.sol#L120). This function will return the fair reserves for each token. Vendor-specific logic is then used to tack any uninvested fees on top of those amounts.\n\nOnce we have the fair reserves and the prices we can compute the token price by:\n\n```\nToken Price = TVL / Token Supply\n            = (r0 * p0 + r1 * p1) / totalSupply\n```\n\n## sqrtPriceX96 Calculation Analysis\n\nThe goal is to check that this calculation does not overflow or lose precision:\n\n```\nuint160 sqrtPriceX96 = sqrt((p0 * 10^UNITS_1 * 2^96) / (p1 * 10^UNITS_0)) * 2^48\n```\n\n\n*Notes:*\n* `p0` and `p1` are uint256 `wad`s, denoting token price in `usd`.\n* We assume that the `sqrt` function does not have overflow or precision problems as it is used in `univ2-lp-oracle` and tested through unit tests.\n\n\n*Analysis:*\n\n1. For numerator expression to not overflow this needs to hold:\n```\n   p0 * 10^UNITS_1 * 2^96 \u003c 2^256                     // 2^96 \u003c 10^29, 2^256 \u003e 10^77 =\u003e\n   p0 * 10^UNITS_1 * 10^29 \u003c 10^77                    // p0 = token0_usd_price * 10^18, UNITS_1 \u003c= 18\n   token0_usd_price * 10^18 * 10^18 * 10^29 \u003c 10^77\n   token0_usd_price \u003c 10^12\n```\n\n2. For the division operation not to lose precision this needs to hold:\n```\n   (p0 * 10^UNITS_1 * 2^96) \u003e\u003e (p1 * 10^UNITS_0) // 2^96 \u003e 10^28, UNITS_1 \u003e= 0, UNITS_0 \u003c= 18\n   (p0 * 10^0 * 10^28) \u003e\u003e p1 * 10^18             // p0 = token0_usd_price * 10^18, p1 = token1_usd_price * 10^18\n   10^10 \u003e\u003e token1_usd_price / token0_usd_price\n```\n\n3. For the full expression not to overflow a uint160 this needs to hold:\n```\n   sqrt((p0 * 10^UNITS_1 * 2^96) / (p1 * 10^UNITS_0)) * 2^48 \u003c 2^160\n   sqrt((p0 * 10^UNITS_1 * 2^96) / (p1 * 10^UNITS_0)) \u003c 2^112         // 2^96 \u003c 10^29, UNITS_1 \u003c= 18, UNITS_0 \u003e= 0, 2^112 \u003e 10^33\n   sqrt((p0 * 10^18 * 10^29) / (p1 * 10^0)) \u003c 10^33\n   sqrt((p0 * 10^18 * 10^29) / p1) \u003c 10^33                            // ^2\n   (p0 * 10^47) / p1 \u003c 10^66\n   (p0 / p1) \u003c 10^19                                                  // p0 = token0_usd_price * 10^18, p1 = token1_usd_price * 10^18\n   token0_usd_price / token1_usd_price \u003c 10^19\n   \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakerdao%2Funiv3-lp-oracle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmakerdao%2Funiv3-lp-oracle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakerdao%2Funiv3-lp-oracle/lists"}