Architecture
The contracts, what each one is for, and how they fit together.
Components
| Contract | Responsibility |
|---|---|
| Univault | ERC-4626 core: shares, NAV, deposit, redeem, and the high-water-mark fee accounting |
| BasketAdapter | Holds the equity basket and executes its trades |
| PriceOracle | Prices holdings in USD and reports staleness |
| KeeperGuard | Enforces every limit before a keeper action runs |
| ExitRouter | Sells a whole position, equities included, to USDG in one transaction |
| BuybackModule | Converts fee revenue into $UNIVAULT and burns what it buys |
user --deposit--> Univault --+--> lending vault (stablecoin leg)
| external ERC-4626
+--> BasketAdapter (equity leg)
^
keeper --> KeeperGuard ------------------+
user --exit--> ExitRouter --> Univault.redeemInKind + v4 swaps --> USDGThere is no separate YieldAdapter or FeeController contract. The lending leg is an external ERC-4626 vault the Univault supplies into directly, and fee accounting lives inside Univault — fewer moving parts, and fewer contracts you have to read to know what happens to your money.
Why it is split up
Adapters exist so the vault does not know or care which lending market or which venue it is using — swapping one out is a deployment, not a rewrite. The guard is separate so the rules governing automation can be read and reasoned about on their own, without picking them out of the vault's accounting logic.