YDS: Architecture
Purpose: Explain the three-layer YDS architecture, how components interact, the delegatecall pattern, and the design invariants that guide YDS authoring.
Audience: Solidity developers with DeFi knowledge who understand YDS concepts and are ready to learn the system architecture before implementing.
Level: Intermediate
Source of truth: Octant v2 codebase—BaseStrategy, TokenizedStrategy, and MultistrategyVault implementations.
Use this page when: You need to understand how YDS components fit together; you want to know what BaseStrategy and TokenizedStrategy do; you're designing a new YDS strategy; you need to explain architecture to team members.
Do not use this page for: Step-by-step lifecycle details; specific hook implementation patterns; practical coding examples; operational workflows (see Mental Model & Lifecycle and Writing a YDS Strategy instead).
- Required: Introduction to YDS
- Helpful: DeFi Concepts Primer (especially the delegatecall section)
YDS reuses Yearn V3’s ERC-4626 design, but changes where profit goes. A YDS is a single-strategy ERC-4626 vault. Instead of compounding profit to depositors, net profit is represented as donation shares minted to a configured donation address. If burning is enabled, losses burn donation shares first up to the available buffer. Your strategy inherits a thin BaseStrategy, overrides three core hooks, and delegates the standardized vault machinery to a shared TokenizedStrategy implementation.
Overview
This page explains the architecture of a Yield Donating Strategy from the point of view of an external DeFi engineer.
The first distinction to keep clear is this:
- a YDS strategy vault is itself an ERC-4626 deposit surface,
- a
MultistrategyVaultis a separate allocator vault that can sit above one or more strategy vaults.
If you are authoring a YDS, you are normally building the first of those two layers.
What YDS inherits from the shared Octant model
YDS keeps several important properties from the shared Octant strategy framework:
- ERC-4626 deposits and withdrawals
- shared accounting and role gating through
TokenizedStrategy - donation-share minting and loss-buffer settlement at
report() - first-deposit minimum-liquidity seeding in the shared YDS implementation
- permissionless composition under multistrategy vaults when needed
That means the strategy author does not rebuild vault accounting or access control from scratch.
What YDS changes versus a normal yield vault
In a normal ERC-4626 yield vault, profit increases depositor value. In YDS, realized profit is redirected to the donation address instead:
- profit is measured during
report(), - new shares are minted to the donation address,
- depositor PPS does not rise from that profit,
- losses burn donation shares first when the buffer exists and burning is enabled.
On the first successful deposit or mint into an empty YDS, the shared implementation permanently locks 1_000 shares at address(0xdead). That protects the initial share ratio from dust-style edge cases. It also means the first depositor receives assets - 1000 shares, not an exact 1:1 share amount.
This is the core architectural change.
Components and layers
1. Strategy vault layer
The strategy vault is the contract you author when building a standalone YDS.
It:
- accepts one underlying asset,
- exposes the ERC-4626 deposit and withdrawal surface,
- integrates one external yield source,
- measures profit and loss,
- settles donation shares during
report().
In the common authoring path, your concrete contract inherits BaseStrategy and keeps only strategy-specific state and logic.
2. Shared implementation layer
Concrete strategies delegate the standardized ERC-4626 mechanics, accounting, and role gating to the shared TokenizedStrategy implementation.
That keeps strategist code small, reuses hardened shared logic, and preserves the Yearn-style pattern of cheap, permissionless deployment of single-asset ERC-4626 strategy vaults.
3. Optional multistrategy vault layer
If your deployment wants one deposit surface across several strategies, a separate allocator vault can sit above them.
In octant-v2-core, that role is served by MultistrategyVault or MultistrategyLockedVault.
That vault layer:
- accepts user deposits,
- allocates debt across attached strategies,
- manages queue policy and rebalancing,
- separately books strategy-level P&L into vault accounting.
This layer is optional from the strategist’s point of view.
The following diagram shows the three-layer architecture and how they interact:
The donation address can be an EOA, Safe, splitter, or forwarder, but it is still the address that receives and, when burn protection is enabled, may later burn strategy shares.
Your strategy contract holds the state (balances, approvals, configuration). The shared TokenizedStrategy contract holds the logic (deposit, withdraw, report, share accounting). When a user interacts with your strategy address, delegatecall makes TokenizedStrategy's code run using your strategy's storage. → Full explanation
The YDS authoring surface
At the BaseStrategy layer, the three core strategy hooks are:
_deployFunds_freeFunds_harvestAndReport
These hooks define the strategy-specific behavior. The rest of the lifecycle is handled by the shared strategy implementation.
Data flow
Standalone strategy vault
User -> YDS strategy vault -> external yield source -> report() -> donation shares minted to donation address
Multistrategy composition
User -> MultistrategyVault -> allocates capital -> YDS strategy vault(s) -> report() -> donation shares minted at strategy layer
The second flow does not turn the YDS into a non-vault component. It only adds a vault layer above it.
Design invariants to internalize
- A YDS is itself a vault. It is not just a helper module behind some other canonical vault.
- One strategy vault, one primary yield logic path. The standalone YDS handles one asset and one strategy integration surface.
- Donation happens at report. Profit becomes donation shares only when accounting is finalized.
- The first YDS deposit seeds minimum liquidity. Empty yield-donating strategies lock
1_000shares ataddress(0xdead); test and preview expectations need to account for this. - Loss protection is conditional. Burning donation shares helps only when it is enabled and the available donation-share buffer is large enough.
- Disable burning through a report when needed. In
1.2.0-develop.15, disabling burn protection from an enabled state can revert withreport before disabling burningwhile pending dragon shares exist; usereportAndDisableBurning()for the atomic operator path. - Multistrategy composition is separate. Allocation across strategies belongs to
MultistrategyVault, not to the standalone YDS contract.
Key takeaway
Think in layers.
When you build YDS, you are usually building a strategy vault. When you need one vault above several strategies, you add a multistrategy vault. “Funding vault” is a useful umbrella phrase for the product pattern, but the concrete deployable surfaces are the strategy vault and the multistrategy vault.