{"id":13485617,"url":"https://github.com/saucepoint/median-oracles","last_synced_at":"2025-07-05T03:36:22.851Z","repository":{"id":183113226,"uuid":"669215322","full_name":"saucepoint/median-oracles","owner":"saucepoint","description":"Experimental variations for a Median Price Oracle with Uni v4","archived":false,"fork":false,"pushed_at":"2023-09-07T14:40:20.000Z","size":53,"stargazers_count":15,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-30T12:41:38.694Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saucepoint.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-21T16:16:27.000Z","updated_at":"2023-12-29T02:47:14.000Z","dependencies_parsed_at":"2024-01-16T09:00:32.274Z","dependency_job_id":"1af1eb90-61ce-4cfd-b5cc-352705147d86","html_url":"https://github.com/saucepoint/median-oracles","commit_stats":null,"previous_names":["saucepoint/median-oracles"],"tags_count":0,"template":false,"template_full_name":"uniswapfoundation/v4-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saucepoint%2Fmedian-oracles","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saucepoint%2Fmedian-oracles/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saucepoint%2Fmedian-oracles/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saucepoint%2Fmedian-oracles/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saucepoint","download_url":"https://codeload.github.com/saucepoint/median-oracles/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251644827,"owners_count":21620630,"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-07-31T18:00:28.102Z","updated_at":"2025-04-30T04:51:01.589Z","avatar_url":"https://github.com/saucepoint.png","language":"Solidity","funding_links":[],"categories":["📜 Examples","📑 Table of Contents"],"sub_categories":["From the Community","From Hackathon"],"readme":"# median-oracles\n### **An experimental suite of Median Price Oracles**\n\n\u003e *from ETHGlobal Paris 2023, built with Uniswap v4 Hooks 🦄*\n\nWhy not use TWAP? lower-liquidity pools are prone to manipulation!\n\n---\n\n| Algorithm                 | Gas (Read)                              |\n|---------------------------|---------------------------------------- |\n| Quickselect               | comically a lot (hundreds of thousands) |\n| Frugal-2U                 | comically a lot (but less than QS)      |\n| Running Frugal-2U         | 4812                                    |\n| Quickselect Time-weighted | TBD                                     |\n| Frugal-2U Time-weighted   | TBD                                     |\n\n\u003e Methodology: obtain 50 *unique* tick observations by running swaps in both directions. Each swap is spaced 12 seconds apart. Use `gasleft()` before and after reading the median\n\n## Median Price Oracle (Quickselect)\n\nThe classic: given a sequence of unordered ticks, fetch the median with the quickselect algorithm\n\n* Uses an O(logn) algorithm on-read\n* Depends on tick observations written to storage\n\n## Frugal Median Price Oracle\n\nApproximates the median using `Frugal-2U` from a sequence of numbers (naive implementation)\n\nFrugal median algorithm compares new numbers against the current approximation and updates the approximation according to a dynamic *step*\n\n* Uses the frugal median-approximation algorithm\n* Depends on tick observations written to storage\n\n## Running Frugal Median Price Oracle\n\nThe gas-optimized implementation of the frugal median approximation: calculating an on-going approximation of the median\n\n* Uses the frugal median-approxiation algorithm\n* Stores the *running* median (approximated) in direct storage\n* *additional research™️ required for windowed support* \n\n### Future work: step-optimization\nIn the frugal median algorithm, the dynamic *step* can be modified to favor stabilization or responsiveness/accuracy. The repo uses 1-tick as a step, but the implementation is set up for additional experimentation\n\n### Future work: time-weighted medians\n\nThe repo is in its early stages and did not have sufficient time to implement time-weighted medians. Time-weighted medians are likely to better represent the price since they account for the duration of a tick (price observation). The repo currently treats unique price observations as having equivalent durations.\n\n\n---\n\n\n```\nsrc/\n├── RunningFrugalMedianHook.sol   Running median approximation\n├── TickObserver.sol              store tick observations for windowed median reads\n├── lens\n│   ├── FrugalMedianLens.sol      read TickObserver and approximate median\n│   └── MedianLens.sol            read TickObserver and calculate true median\n└── lib\n    ├── FrugalMedianLibrary.sol   median approximation library\n    ├── MedianLibrary.sol         median calculation library (quickselect)\n    └── RingBufferLibrary.sol     optimized ring buffer for price observations\n\ntest/\n├── FrugalMedianLens.t.sol        test the naive frugal median\n├── MedianLens.t.sol              test the true median (quickselect)\n├── RunningMedian.t.sol           test the running median approximation\n├── TickObserver.t.sol            test the tick observer\n├── implementation\n│   ├── ...                       Uniswap overrides for testing\n├── median\n│   ├── FrugalMedianTest.t.sol    test frugal median algo\n│   └── MedianLibrary.t.sol       test quickselect algo\n└── utils\n    ├── HookTest.sol\n    └── RingBuffer.t.sol          test ring buffer\n```\n\n---\n\nAdditional resources:\n\n[v4-periphery](https://github.com/uniswap/v4-periphery) contains advanced hook implementations that serve as a great reference\n\n[v4-core](https://github.com/uniswap/v4-core)\n\n---\n\n*requires [foundry](https://book.getfoundry.sh)*\n\n```\nforge install\nforge test\n```\n\n---\n\nCredits\n\n* [Frugal Streaming for Estimating Quantiles:One (or two)\nmemory suffices](https://arxiv.org/pdf/1407.1121v1.pdf)\n\n* [euler-xyz/median-oracle](https://github.com/euler-xyz/median-oracle) and [median oracle discussions](https://ethresear.ch/t/median-prices-as-alternative-to-twap-an-optimised-proof-of-concept-analysis-and-simulation/12778)\n\n* [Uniswap v3 TWAP Oracles in Proof of Stake](https://blog.uniswap.org/uniswap-v3-oracles)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaucepoint%2Fmedian-oracles","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaucepoint%2Fmedian-oracles","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaucepoint%2Fmedian-oracles/lists"}