Deposits and Withdrawals During Active Strategy
When a strategy is live (proposal inExecuted state), redemptionsLocked() returns true. The vault uses a two-lane model to keep liquidity available without trusting unverified prices:
- Lane A (oracle instant): instant deposit / redeem at a live oracle price via the governance-owned PriceRouter — available when every position kind is priced live and
laneAEnabled[kind] == true. Lane A depositors receive a per-share lockup until the proposal settles (G1 MEV protection). - Lane B (async queue):
requestDeposit/requestRedeemescrow assets/shares inVaultWithdrawalQueue, then settle at the frozen per-proposal price after the proposal ends. The universal fallback — always available.
rescueERC20 is blocked during active proposals regardless of lane.
See Deposits & Withdrawals for the full flow diagram, lane preconditions, claim mechanics, and per-strategy Lane A status.
WOOD/SHARES early-exit pool — aspirational, not live. An earlier design proposed one-sided liquidity pools pairing WOOD with each vault’s share token, letting depositors swap out of locked vaults at a market-discovered discount. That design is not implemented; the Lane B async queue is the primary exit path during a proposal. Early-exit liquidity is tracked for a future release.
WOOD Tokenomics (ve(3,3) stack)
The protocol ships a full ve(3,3)-style token economy (VotingEscrow, Voter, SyndicateGauge, Minter, VoteIncentive, RewardsDistributor, VaultRewardsDistributor) in addition to the governance + fee logic on this page. The surface is live in contracts/src/ but the public documentation is deliberately deferred — the surface is still stabilising around PR #229 (guardian rewards) and the early-exit design above.
Expanded ve(3,3) docs are forthcoming. See the in-repo reference
docs/tokenomics-wood.md for the current internal description of lock mechanics, gauge weights, bribe flows, rebase math, and Minter emissions. A dedicated tokenomics section will be added to these public docs as the surface stabilises.SyndicateGauge.claimLPRewardsalways reverts (_calculateLPRewardis stubbed). Gauge LP reward accrual is tracked but not claimable. Slices that already accrued under the legacy bootstrap schedule (epochs ≤ 12) can be recovered by the gauge owner viarescueStuckLPRewards(epoch, recipient)— emissions for new epochs no longer accrue to this slice (getLPRewardPercentagereturns 0).- Price and lock-ratio circuit breakers in
Minterare manual (multisig) today, not triggered automatically. - No WOOD/SHARES Uniswap V3 early-exit pool is deployed; the design in older drafts is not live.
- Guardian Block-side WOOD epoch rewards are distributed off-chain via Merkl. The registry emits
BlockerAttributed(proposalId, epochId, blocker, weight)per blocker on a resolved-blocked review; Merkl’s bot reads these (plus delegation / commission events) to build Merkle roots, and guardians claim at merkl.xyz. There is no on-chainfundEpoch/claimEpochReward/sweepUnclaimed(see Guardian Review).
Fee Structure
Three fees are distributed from strategy profits at settlement:| Fee | Recipient | Set by | Purpose |
|---|---|---|---|
| Protocol fee | protocolFeeRecipient | ProtocolConfig owner (protocol multisig) | Protocol revenue |
| Performance fee | Agent (proposer) | Vault owner — one agentFeeBps per vault (default 5%) | Incentivize good strategy proposals |
| Management fee | Vault owner | Factory (per-vault, configurable) | Incentivize vault operation and curation |
Self-managed-fee strategies (custody model)
The three fees above are the governor’s settle-fee path — computed atsettleProposal from the vault’s realized float delta. A custody strategy — one where LPs deposit and redeem directly at the strategy, and the strategy mints/burns vault shares itself (via strategyMint / strategyBurn) — breaks that model: the governor’s balanceOf(vault) − snapshot PnL would misread net deposits as profit and double-charge. Such a strategy signals IStrategy.selfManagesFees() == true, and the governor’s _finishSettlement skips _distributeFees entirely for that proposal:
- All settle-fees are skipped — protocol, guardian, agent, and management.
- The strategy manages its fees internally, crystallizing them as share dilution (e.g. a streaming management fee plus a per-share high-water-mark performance fee minted as fee-shares).
- Protocol and guardian fees for custody strategies are handled off-chain as a follow-up — they are not routed through the governor.
selfManagesFees() defaults to false (BaseStrategy), so every non-custody strategy uses the governor settle-fee path described in the rest of this section. The Leveraged Aerodrome CL strategy is the first selfManagesFees() == true template.
Protocol Fee
A protocol-level fee taken from gross profit before agent and management fees. This funds protocol development and operations.protocolFeeBps— percentage of gross profit taken as protocol fee (max 10% / 1000 bps,MAX_PROTOCOL_FEE_BPS)protocolFeeRecipient— address that receives the protocol fee- Both live on the global
ProtocolConfigcontract (protocol-multisig-owned), not the per-vault governor. Each vault’s governor reads them at propose time and snapshots them into the proposal (snapshotProtocolFeeBps/snapshotProtocolFeeRecipient), so settlement charges the rate voters saw even if the config changes mid-flight. setProtocolFeeBps/setProtocolFeeRecipientareonlyOwneronProtocolConfig(Ownable2Step, the protocol multisig) and emitParameterChangeFinalized(paramKey, old, new)/ProtocolFeeRecipientSet. Recipient coupling is enforced in both directions: setting a nonzeroprotocolFeeBpsrequiresprotocolFeeRecipientfirst, and the recipient cannot be cleared whileprotocolFeeBps > 0.
Performance (agent) fee
The performance fee is the cut a proposing agent earns on net profit (after the protocol fee). It is a vault-level property, not a per-proposal value — the vault owner sets one fee for the whole vault and every proposal inherits it.agentFeeBpslives on the vault, not the proposal. Set it withvault.setAgentFeeBps(bps)(owner only) or the CLIsherwood syndicate set-agent-fee --bps <bps>.- Defaults to 5% (500 bps) at vault creation. Capped at 15% (1500 bps) by the vault.
- When a proposal is created the governor snapshots the vault’s current
agentFeeBpsonto that proposal (immutable for that proposal — a later owner change cannot alter an already-created proposal). At settlement the governor uses that snapshot, additionally clamped tomaxPerformanceFeeBps. A change therefore only takes effect for proposals created after it. propose()takes no fee argument. To split the fee among collaborators, use co-proposers (see Collaborative Proposals).
Fee distribution order
Fees are calculated and distributed in a strict order — protocol fee first, then agent fee, then management fee:Management Fee
The management fee incentivizes vault operation — the owner curates agents, manages parameters, handles emergencies.managementFeeBps— configurable per-factory (max 10% / 1000 bps)- Applied to new vaults at creation time
- Owner only earns on profit — aligned with depositor outcomes
Try/catch fee transfers + unclaimed-fee escrow
Every fee transfer — protocol fee, agent / co-proposer performance fee, and vault owner management fee — is wrapped in try/catch aroundvault.transferPerformanceFee(asset, recipient, amount). If the transfer reverts (USDC blacklist, paused token, contract recipient with a failing receive, etc.) the governor:
- Credits the owed amount to an on-chain escrow keyed by
keccak256(vault, recipient, token) - Emits
FeeTransferFailed(recipient, token, amount)so indexers can surface the stuck fee - Continues settlement without reverting
claimUnclaimedFees(vault, token) once the failure condition is cleared (they un-blacklist, rotate the recipient, unpause, etc.). Keying by origin vault means a recipient can only claim against the specific vault whose transfer failed. Read via unclaimedFees(vault, recipient, token).
This ensures:
- Depositor capital is never held hostage by a blacklisted fee recipient — settlement always completes
- Fees are not lost — they are escrowed on the governor and pullable by the rightful recipient
- Every recipient gets the same protection (protocol, agent, co-proposers, vault owner)
test/governor/FeeBlacklistResilience.t.sol.
Safety: the vault’s agentFeeBps is capped at 1500 bps (15%) by the vault and additionally clamped to maxPerformanceFeeBps (governor parameter) at settlement. protocolFeeBps is capped at 1000 bps (10%). managementFeeBps is capped at 1000 bps (10%) and set at the factory level.
Why a management fee? Without it, there is no incentive to operate a vault — the owner curates agents, manages targets, sets parameters, handles emergencies, but earns nothing. The management fee aligns vault owner incentives with depositor outcomes (owner only earns on profit).
Single Strategy Per Vault
Only one strategy can be live (Executed state) per vault at a time. This simplifies capital accounting, eliminates cross-strategy risk, and makes the redemption lock/cooldown model clean.- Governor tracks
activeProposal[vault]— the currently executing proposal ID (0 if none) executeProposalreverts ifactiveProposal[vault] != 0executeProposalalso reverts if the vault is in its cooldown window- Multiple proposals can be in Pending/Approved state simultaneously — they queue up
- Only one can be executed at a time
Open Design Questions
Strategy Carry Model
Two possible models: A. Vault-level performance fee (current design)- Vault owner sets one
agentFeeBpsfor the vault (default 5%); each proposal snapshots it at propose time - Snapshot clamped to
maxPerformanceFeeBpsat settlement - Fee paid on settlement from profits only
- Simple, clear, owner-controlled
- Strategy creators earn ongoing % of all TVL running their strategy
- More DeFi-native (like Uniswap LP fees)
- Needs TVL tracking, streaming payments, strategy template integration
What Happens if a Strategy Loses Money?
- Agent earns nothing (performance fee only applies to profits)
- Loss is socialized across all shareholders (standard fund behavior)
- Loss is recorded on-chain via the
ProposalSettled(uint256 indexed proposalId, address indexed vault, int256 pnl, uint256 performanceFee, uint256 duration)event emitted by_finishSettlement— indexers can aggregate into per-agent track records. A dedicatedSTRATEGY_PNLEAS attestation for richer agent reputation is planned and is NOT shipped in V1. - No slashing mechanism in V1 for agents — see Guardian Review for the separate guardian / vault-owner slashing layer.