Common Vault Operations
Day-to-day vault management — roles, contracts, guards, and recommended multisig thresholds
Overview — Day-to-day vault management flow
Operation Details
allocate(strategy, amount)
Move idle assets from FundVault to a whitelisted strategy
CURATOR — 2/3 MULTISIG
| Property | Detail |
|---|---|
| Contract | FundVault.allocate(strategy, amount) |
| Role | CURATOR_ROLE — 2/3 multisig (Frank, Bean, Khiem) |
| Timelock | NONE — operational frequency, bounded by cap |
| Guards |
strategy.totalAssets() + amount ≤ strategyCap •
strategy must be whitelisted •
idleAssets ≥ amount •
isNotPaused • nonReentrant
|
| Effect | Transfers asset to strategy via safeTransfer • increments totalAllocated[strategy] |
| Risk | High — moves real assets out of FundVault, but capped |
deallocate(strategy, amount)
Pull assets from a strategy back to FundVault
CURATOR — 2/3 MULTISIG
| Property | Detail |
|---|---|
| Contract | FundVault.deallocate(strategy, amount) |
| Role | CURATOR_ROLE — 2/3 multisig (Frank, Bean, Khiem) |
| Timelock | NONE — needed frequently for rebalancing & pre-fulfill |
| Guards |
Strategy must be whitelisted •
amount > 0 •
isNotPaused • nonReentrant
|
| Effect | Calls strategy.withdraw(amount) which transfers assets back to FundVault • increments totalDeallocated[strategy] |
| Risk | High — triggers strategy withdrawal; may cause slippage if strategy holds illiquid positions |
setStrategyCap(strategy, cap)
Set the maximum amount that can be allocated to a strategy
CURATOR — 2/3 MULTISIG
| Property | Detail |
|---|---|
| Contract | FundVault.setStrategyCap(strategy, cap) |
| Role | CURATOR_ROLE — 2/3 multisig (Frank, Bean, Khiem) |
| Timelock | TIMELOCKED — cap changes affect risk exposure, requires delay |
| Guards | Strategy must be whitelisted • calls _timelocked() |
| Effect | Sets strategyCap[strategy] = cap • enforced as hard ceiling in allocate() |
| Risk | High — raising cap exposes more capital; setting to 0 effectively blocks all future allocations |
fulfillRedeem(totalAmount, controllers)
Fulfill pending redeem requests — pull assets from FundVault and mark requests claimable
OPERATOR — 2/3 MULTISIG
| Property | Detail |
|---|---|
| Contract | AssetVault.fulfillRedeem(totalAmount, controllers[]) |
| Role | OPERATOR_ROLE — 2/3 multisig (Frank, Bean, Max) |
| Timelock | NONE — frequent ops; PPS guard protects against stale fulfills |
| Guards |
isNotPaused • nonReentrant •
FundVault must have idleAssets ≥ totalAmount for releaseAssets()
|
| Effect |
1. Calls FundVault.releaseAssets(totalAmount) — pulls assets into AssetVault2. Calls AsyncRequestManager.fulfillRedeem(controllers) — marks each request as fulfilled3. Users can now call redeem() or withdraw() to claim
|
| Risk | Medium — moves assets to user-claimable state; bounded by existing request amounts |
syncNavValue(asset, description, nav)
Update off-chain NAV for a specific category on FundNavFeed — e.g. the current value held by a strategy
OPERATOR — 2/3 MULTISIG
| Property | Detail |
|---|---|
| Contract | FundNavFeed.syncNavValue(asset, description, nav) |
| Role | OPERATOR_ROLE — 2/3 multisig (Frank, Bean, Max) |
| Timelock | NONE — frequent updates; bounded by PPS deviation guard in updateNav() |
| Guards |
Category must exist for the asset (_getCategoryIndex) •
category must be registered via addNavCategory()
|
| Effect | Sets _categories[asset][index].nav = nav • emits NavUpdated(asset, nav, description) |
| Risk | High — directly affects totalNAV and PPS calculation; bad values caught by PPS deviation guard on next updateNav() |
| When to call | Before updateNav() — sync the current value of assets held by each strategy so NAV reflects real positions |
updateNav()
Recompute protocol-wide NAV, validate PPS deviation, persist new price-per-share
OPERATOR — 2/3 MULTISIG
| Property | Detail |
|---|---|
| Contract | VaultManager.updateNav() |
| Role | OPERATOR_ROLE — 2/3 multisig (Frank, Bean, Max) |
| Timelock | NONE — frequent ops; PPS deviation guard is the safety net |
| Guards |
isValidPps check — reverts with InvalidPricePerShare if new PPS deviates beyond deviationPps threshold
|
| Effect |
1. Calls navAggregateModel.computeNav() across all registered assets2. Persists per-asset NAVs, navDenomination, effNavDenomination, globalRedeemShares3. Updates pricePerShare and lastNavUpdated timestamp4. Emits PricePerShareUpdated(oldPps, newPps)
|
| Risk | Medium — bounded by deviation guard; stale inputs from syncNavValue are the real risk vector |
| When to call | After every allocate / deallocate / syncNavValue — keeps PPS accurate for deposits, redeems, and fee calculations |
Operational checklist:
• Before first allocate — Curator must
• Before updateNav — Operator must call
• After allocate / deallocate — Operator must call
• Before fulfillRedeem — ensure FundVault has sufficient idle assets. If not, Curator must
• Cap = 0 blocks future allocations but does not force an automatic deallocate — existing positions remain until explicitly withdrawn
• Before first allocate — Curator must
setStrategyCap() (timelocked) and strategy must be whitelisted via addStrategy()• Before updateNav — Operator must call
syncNavValue() on FundNavFeed for each strategy whose position value has changed• After allocate / deallocate — Operator must call
syncNavValue() then updateNav() to keep PPS in sync• Before fulfillRedeem — ensure FundVault has sufficient idle assets. If not, Curator must
deallocate() from a strategy first• Cap = 0 blocks future allocations but does not force an automatic deallocate — existing positions remain until explicitly withdrawn
Suggested multisig key owners:
• CURATOR_ROLE (2/3) — Frank, Bean, Khiem (or other wallets owned by Frank or Bean as alternates)
• OPERATOR_ROLE (2/3) — Frank, Bean, Max
• CURATOR_ROLE (2/3) — Frank, Bean, Khiem (or other wallets owned by Frank or Bean as alternates)
• OPERATOR_ROLE (2/3) — Frank, Bean, Max