-
Notifications
You must be signed in to change notification settings - Fork 1
feat(aave): harden v3 oracle guard and add v4 protections #105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
makemake-kbo
wants to merge
9
commits into
master
Choose a base branch
from
makemake/eng-4182-spikesoleng-revisit-aave-v3-assertions-map-aave-v4
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
6a74798
fix(aave): harden v3 Horizon oracle guard
makemake-kbo b658045
feat(aave): add v4 protection assertions
makemake-kbo 15f9d2c
fix(aave): support legacy weETH implementation
makemake-kbo 08b9359
refactor(aave): remove v4 external-collateral reduce-only assertions
makemake-kbo 15585cc
docs(aave): add realized 24h net-flow chart for v4 circuit-breaker ca…
makemake-kbo 42a7959
fix(aave): include accrued treasury backing liability
makemake-kbo 00330d9
fix(aave): harden v3 Horizon oracle guard
makemake-kbo c8f82c9
fix(aave): fail closed on skipped oracle reads
makemake-kbo 1e08b44
fix(aave): close remaining review gaps
makemake-kbo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| # Aave V4 consumed-oracle assertion deployment | ||
|
|
||
| `AaveV4EthereumMainSpokeOracleAssertion` is pinned to Ethereum Main Spoke state | ||
| at block 25,646,732 and Aave V4 release `v0.5.11`. | ||
|
|
||
| ## Constructor | ||
|
|
||
| ```solidity | ||
| new AaveV4EthereumMainSpokeOracleAssertion( | ||
| maxTraceCalls, | ||
| deviationBpsByReserveId, | ||
| extraVerifiedConfigSlots | ||
| ); | ||
| ``` | ||
|
|
||
| - `maxTraceCalls`: transaction-wide maximum for committed | ||
| `getReservePrice` calls and configured-source `latestAnswer` calls. `64` is a | ||
| practical initial value for the 14-reserve Main Spoke and two full price | ||
| sweeps. Lower values reduce worst-case work but reject larger multicalls. | ||
| - `deviationBpsByReserveId`: 14 tolerances ordered by reserve ID: | ||
| WETH, wstETH, weETH, WBTC, cbBTC, AAVE, LINK, USDC, USDT, EURC, RLUSD, USDG, | ||
| frxUSD, GHO. Zero means exact equality with the PreTx price. A value of 100 | ||
| permits `[99%, 101%]`, with conservative rounding at both bounds. | ||
| - `extraVerifiedConfigSlots`: additional `(target, slot)` guards. The wrapper | ||
| already includes all 22 verified mutable Chainlink/CAPO routing slots in the | ||
| pinned source graph. Do not add guesses; document the upstream layout and | ||
| deployed bytecode for every extra slot. | ||
|
|
||
| The constructor rejects a zero target, zero trace bound, more than 64 policies, | ||
| more than 128 total config guards, duplicate guards, duplicate direct sources, | ||
| non-contiguous reserve IDs, zero assets/sources, and tolerances at or above | ||
| 10,000 bps. | ||
|
|
||
| ## Adoption checklist | ||
|
|
||
| Before activation: | ||
|
|
||
| 1. Confirm chain ID 1 and Main Spoke | ||
| `0x94e7A5dCbE816e498b89aB752661904E2F56c485`. | ||
| 2. Re-read the ERC-1967 implementation slot and require | ||
| `0xABd0E26FE17BDe4F1f1187Ed8aA80C274E03D8b5`. | ||
| 3. Require `ORACLE()` to equal | ||
| `0x99B2B6CEa9C3D2fd8F4d90f86741C44B212a6127`, oracle `spoke()` to point back | ||
| to Main Spoke, and oracle decimals to equal 8. | ||
| 4. Re-read all 14 reserves and direct sources and compare them with the | ||
| production wrapper. | ||
| 5. Review the source graph and built-in config slots against verified deployed | ||
| source. Rebuild the wrapper after any upstream migration. | ||
| 6. Choose asset-specific tolerances. Zero is appropriate only when legitimate | ||
| within-transaction source movement is impossible or should be blocked. | ||
| 7. Run the focused PCL suite with `-vvvv`; confirm parent/child call IDs and | ||
| outputs are still exposed as documented. | ||
| 8. Measure a worst-case multicall under the production executor. The current | ||
| 14-reserve/two-sweep fixture measures 2,881,782 gas. | ||
|
|
||
| At runtime, the assertion validates policy completeness and exact PreTx | ||
| reserve/source identity before accepting a committed price read. A legitimate | ||
| reserve addition, source update, proxy rotation, CAPO parameter update, or | ||
| Spoke upgrade intentionally blocks risk-sensitive operations until a reviewed | ||
| replacement assertion is deployed. | ||
|
|
||
| ## Generic deployments | ||
|
|
||
| `AaveV4OracleConsumptionAssertion` can protect another verified V4 Spoke, but | ||
| the caller must provide: | ||
|
|
||
| - the exact Spoke adopter; | ||
| - the oracle selected by that implementation; | ||
| - the expected Spoke implementation; | ||
| - a complete reserve policy with unique direct sources; and | ||
| - verified storage guards for every mutable router, proxy, adapter, fallback, | ||
| or provider slot that can change a consumed price. | ||
|
|
||
| Do not copy the Ethereum Main Spoke asset list, sources, implementation, or | ||
| storage guards to another Spoke or chain. See the accompanying | ||
| [research note](research/aave-v4-oracle-consumption-protection-2026-07-30.md) | ||
| for the exact source and trace evidence. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
examples/aave/research/aave-v4-flow-rate-calibration-2026-07-30.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # Aave v4 flow-rate circuit-breaker calibration | ||
|
|
||
| Snapshot date: 2026-07-30<br> | ||
| Chain: Ethereum mainnet<br> | ||
| Historical block range: 25,430,974–25,646,159<br> | ||
| Lookback: 30 days | ||
|
|
||
| ## Asset selection | ||
|
|
||
| The three assets were selected from DefiLlama's aggregate Aave v4 token TVL: | ||
|
|
||
| | Rank | Asset | Aggregate token TVL | | ||
| | --- | --- | ---: | | ||
| | 1 | WBTC | $52.35m | | ||
| | 2 | USDG | $30.84m | | ||
| | 3 | wstETH | $29.40m | | ||
|
|
||
| DefiLlama derives Aave v4 TVL from ERC20 balances held by the Core, Plus, and | ||
| Prime Hubs. WBTC and wstETH are split between Core and Prime, so both Hubs need | ||
| their own adopter-scoped watchers. USDG is held only by Core. | ||
|
|
||
| Sources: | ||
|
|
||
| - <https://defillama.com/protocol/aave-v4> | ||
| - <https://api.llama.fi/protocol/aave-v4> | ||
| - <https://github.com/DefiLlama/DefiLlama-Adapters/blob/main/projects/aave-v4/index.js> | ||
|
|
||
| ## Methodology | ||
|
|
||
| For each Hub/token pair: | ||
|
|
||
| 1. Query every ERC20 `Transfer` to and from the Hub during the 30-day range. | ||
| 2. Reconstruct the Hub balance at the beginning of the range from the current | ||
| balance and the net transfer flow. | ||
| 3. Calculate the maximum rolling 24-hour net directional flow as basis points | ||
| of the Hub balance immediately before the window's first transfer. | ||
| 4. Bucket net flow into 10-second intervals and calculate the peak flow rate as | ||
| basis points of the Hub balance per second. | ||
| 5. Set each production limit to `ceil(observed maximum × 1.20)`. | ||
|
|
||
| This intentionally calibrates to the maximum observed window rather than the | ||
| 30-day daily average. A breaker set from the average would have rejected | ||
| legitimate historical spikes. | ||
|
|
||
| The Phylax cumulative watcher measures net flow: inflows offset outflows and | ||
| vice versa. It does not cap gross volume. The peak-rate signal is experimental | ||
| and comes from the same 10-second buckets. | ||
|
|
||
| ## Results | ||
|
|
||
| | Hub | Asset | Current balance | 30d gross in | 30d gross out | Max 24h net in | In limit | Max 24h net out | Out limit | Peak in rate | In-rate limit | Peak out rate | Out-rate limit | | ||
| | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | ||
| | Core | WBTC | 670.9402 | 129.0485 | 20.8481 | 986.44 bps | 1,184 bps | 91.41 bps | 110 bps | 39.32 bps/s | 48 bps/s | 7.22 bps/s | 9 bps/s | | ||
| | Core | USDG | 30.6733m | 68.6104m | 61.5900m | 4,329.38 bps | 5,196 bps | 4,472.00 bps | 5,367 bps | 438.64 bps/s | 527 bps/s | 128.27 bps/s | 154 bps/s | | ||
| | Core | wstETH | 8,490.4974 | 4,365.9474 | 1,416.9640 | 1,587.63 bps | 1,906 bps | 776.51 bps | 932 bps | 47.57 bps/s | 58 bps/s | 77.62 bps/s | 94 bps/s | | ||
| | Prime | WBTC | 136.7563 | 57.6882 | 47.4818 | 1,750.94 bps | 2,102 bps | 2,026.00 bps | 2,432 bps | 123.91 bps/s | 149 bps/s | 148.27 bps/s | 178 bps/s | | ||
| | Prime | wstETH | 3,840.5454 | 2,142.8947 | 1,233.7078 | 2,903.51 bps | 3,485 bps | 757.23 bps | 909 bps | 175.60 bps/s | 211 bps/s | 60.15 bps/s | 73 bps/s | | ||
|
|
||
| The observed maxima used for these constants are checked in as | ||
| `aave-v4-flow-rate-observed-maxima.csv`; `calculate-aave-v4-flow-limits.py` | ||
| recomputes every limit as `ceil(observed × 1.20)`. The table and chart were | ||
| reconciled to that artifact, notably for Core USDG and Prime WBTC outflow. | ||
|
|
||
| ## Operational notes | ||
|
|
||
| - The assertion uses a 1 bps cumulative dispatch floor so the custom rate check | ||
| executes well before any calibrated limit. The policy trips if either the | ||
| cumulative limit or peak-rate limit is exceeded. | ||
| - The trigger is currently unarmed because net-flow dispatch can fail to select | ||
| the directional rate assertion after opposite-direction flow in the same | ||
| window. Keep this policy staged until absolute directional or rate-native | ||
| dispatch is available. | ||
| - Apply the Core assertion to the Core Hub and the Prime companion assertion to | ||
| the Prime Hub. Adopting either assertion on another address fails explicitly. | ||
| - Recalibrate before production rollout and after material cap, asset-mix, or | ||
| flow-regime changes. Thirty days is a useful initial sample, not a permanent | ||
| risk parameter. | ||
| - `inflowRate()` and `outflowRate()` require | ||
| `AssertionSpec.Experimental`; the public Phylax docs describe Experimental as | ||
| unrestricted and potentially untested. This draft should remain staged until | ||
| the runtime support and production policy are confirmed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| hub,asset,in_window_bps,out_window_bps,in_peak_rate_bps,out_peak_rate_bps | ||
| Core,WBTC,986.44,91.41,39.32,7.22 | ||
| Core,USDG,4329.38,4472.00,438.64,128.27 | ||
| Core,wstETH,1587.63,776.51,47.57,77.62 | ||
| Prime,WBTC,1750.94,2026.00,123.91,148.27 | ||
| Prime,wstETH,2903.51,757.23,175.60,60.15 |
Binary file added
BIN
+182 KB
examples/aave/research/aave-v4-flow-rate-realized-flows-2026-07-30.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.