docs: add TIB for Vault V2 public-allocator shared liquidity - #912
docs: add TIB for Vault V2 public-allocator shared liquidity#912Foulks-Plb wants to merge 5 commits into
Conversation
| - Should `getPublicReallocationLiquidityVaultV2` count idle by default? It is included here, on the | ||
| grounds that idle is genuinely reallocatable and excluding it under-reports — but a dashboard | ||
| showing "shared liquidity" may prefer to attribute idle separately. | ||
| - Should reallocation candidates be favored by penalty cost? Unlike PAV1's single per-vault fee, |
There was a problem hiding this comment.
Open question before start (Should reallocation candidates be favored by penalty cost?)
(https://morpholabs.slack.com/archives/C0AJMKR8VB9/p1785398315187139)
29f6a32 to
b2d0b3d
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 29f6a3248b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| `BluePublicAllocator` is a singleton — no constructor, no immutables, no `MORPHO` reference. Every | ||
| entry point is gated on `IVaultV2(vault).isAllocator(msg.sender)`; there is no `admin` mapping. |
There was a problem hiding this comment.
Describe allocator calls as permissionless
In the pinned allocator, reallocate and allocateFromIdle are the public, penalty-paid entry points; they check msg.value, active adapters, and deallocation/idle flags, not IVaultV2(vault).isAllocator(msg.sender) (that guard is on the curator setters). Describing every entry point as allocator-gated can lead the SDK surface/JSDoc to treat public reallocations as curator-only and hide a permissionless flow.
Useful? React with 👍 / 👎.
| - `absoluteCap[t] > 0` for every target id (`ZeroAbsoluteCap`), `allocation[s] > 0` for every source | ||
| id (`ZeroAllocation`). | ||
| - For each id **shared** between source and target: | ||
| `allocation[id] + untracked_src + untracked_tgt ≤ min(absoluteCap[id], mulDivDown(A, relativeCap[id], WAD))`. |
There was a problem hiding this comment.
Bypass the relative-cap bound at WAD
When relativeCap is WAD, the on-chain cap check skips the relative-cap bound (relativeCap == WAD || ...), but this shared-id formula still takes min(..., A) and therefore caps the id at firstTotalAssets. For vaults where firstTotalAssets is below a valid absolute-capped allocation, the planner would reject or undercount reallocations that the contract accepts; use the absolute cap alone in the WAD case.
Useful? React with 👍 / 👎.
| | `allocations[vault][t]`, all 3 target ids | `+= change_tgt = assets + untracked_tgt` | same | | ||
| | `markets[srcId]`, `srcAdapter.supplyShares` | `withdraw(assets)` | — | | ||
| | `markets[tgtId]`, `tgtAdapter.supplyShares` | `supply(assets)` | same | | ||
| | `vault.assetBalance` | `+= assets + untracked_src`, then `−= assets` | `−= assets` | |
There was a problem hiding this comment.
Keep untracked interest out of idle balance
In a market→market leg, the pinned VaultV2 receives exactly assets from the deallocate adapter and then sends exactly assets to the allocate adapter, while untracked_src only changes the returned cap allocation. Adding untracked_src to vault.assetBalance creates fake idle liquidity in the simulated state, so a later idle→market withdrawal in the same greedy plan can be emitted even though the vault never received those tokens and will revert.
Useful? React with 👍 / 👎.
Freezes the design of a Vault V2 mirror of the V1 PublicAllocator shared-liquidity engine, based on the new BluePublicAllocator periphery contract in morpho-org/vault-v2. Additive only: the V1 surface is untouched, the new symbols mirror V1 names with a VaultV2 suffix, and the engine is deliberately not wired into any transaction flow (deferred to the blue bundles migration). Records the contract-level finding that VaultV2 rebases allocation[id] to expectedSupplyAssets rather than incrementing it, so shared allocation ids do not net to zero across a reallocation and allocation[id] never bounds the deallocate leg. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
b2d0b3d to
7d4a219
Compare
Motivation
The SDK can answer "how much more can be borrowed on this Blue market, counting liquidity a public allocator could pull in?" for MetaMorpho Vault V1 only —
ReallocationData→computeReallocations→VaultReallocation[].morpho-org/vault-v2has since shippedBluePublicAllocator(last touchedb417825, 2026-07-29), for which the SDK has no ABI, address key, entity, or compute — so as Vault V2 TVL grows, the V1-only engine silently under-reports a market's reallocatable liquidity and quotes borrows as impossible when they would succeed.Solution
This PR is documentation only — one new TIB, no package source touched, no changeset (root
AGENTS.md§7 excludes non-API documentation-only changes). It freezes the design of a Vault V2 mirror that is strictly additive: the V1 surface is untouched (no renames, no deprecations, no breaking change), the new symbols mirror V1 names with aVaultV2suffix (computeReallocationsVaultV2,ReallocationDataVaultV2, …), and the engine is deliberately not wired into any transaction flow — no action, no bundler encoder, andMorphoBlue.getReallocationData()keeps its exact current behavior, with the v1/v2 dispatch deferred to the blue bundles migration.The load-bearing part is a contract-level finding verified line-by-line against
VaultV2.solandMorphoMarketV1AdapterV2.sol: the vault rebasesallocation[id]toexpectedSupplyAssetsrather than incrementing it byassets, which means shared allocation ids (adapterId,collateralId) do not net to zero across a reallocation andallocation[id]never bounds the deallocate leg. The intuitive port of the V1 algorithm is therefore wrong in the unsafe direction, and the TIB records it as rejected Alternative 4 with an invariant test per trap.Review notes
Six locked decisions worth a second opinion, all argued in Considered Alternatives: the sibling-class-over-parameterized-
ReallocationDatasplit, the vault-grouped result shape, full-parity cap simulation, the shared-id correction above, deferring the encoder, and dropping V1's four deprecated utilization options. Two Open Questions are left for reviewers: whetherBluePublicAllocatorgets a deterministic cross-chain address, and whether the liquidity metric should count vault idle by default.