In Morpho Vault V2, cap setters accept raw idData bytes and hash them internally; allocation and cap getters accept the resulting bytes32 ID. For MorphoMarketV1AdapterV2, adapter and market IDs include the adapter address, while the collateral ID does not. The collateral key can therefore combine allocations across adapters that report that same ID within one vault.
Identify the adapter before encoding a cap
This explanation follows Morpho Vault V2 and its MorphoMarketV1AdapterV2, which routes assets into Blue variable-rate markets. The reference is official repository commit da1a165, checked on 29 October 2026. Match a real vault and its adapters to their deployed implementations before applying these formulas.
The adapter returns three IDs for a market. Let A mean its own contract address and P mean the complete MarketParams tuple. A preimage is the exact byte sequence supplied to the hash. Morpho's adapter curation documentation specifies these preimages, each hashed with Keccak-256:
| Cap scope | Raw idData construction | Exposure grouped under the key |
|---|---|---|
| Adapter | ABI-encode string this, then address A | Allocations through A |
| Collateral | ABI-encode string collateralToken, then P's collateral address | Allocations reporting that collateral key |
| Adapter plus market | ABI-encode string this/marketParams, address A, then tuple P | That market position through A |
The strings are exact, case-sensitive values. A is the adapter address. Solidity's address(this) in the pinned ID implementation refers to that adapter.
P's fields, in order, are loanToken, collateralToken, oracle, irm and lltv. The first four are addresses; lltv is uint256. That order comes from the locked Blue interface, which the selected Vault V2 source imports.
These cap allocations measure the vault's underlying loan asset. They are separate from Blue's internal supply-share counts, whose conversion is covered in Morpho Blue supply shares versus assets. A cap named for collateral still limits loan-asset exposure to positions backed by that collateral; its amount is not a count of collateral tokens.
Keep allocation data, idData and the hash separate
There are three byte sequences to distinguish. For this adapter, allocate receives data containing ABI-encoded P alone. Its code decodes that tuple and returns the three cap IDs above. The adapter interface lets one operation report multiple risk identifiers and a signed allocation change.
Cap setters instead receive one chosen raw idData preimage. For example, an adapter-wide cap uses the encoding of this and A, without P. Finally, getters receive the 32-byte hash of that preimage. The Vault V2 interface makes the argument types explicit:
| Intended action | Byte argument |
|---|---|
| Increase or decrease an absolute cap | Raw idData |
| Increase or decrease a relative cap | Raw idData |
Read absoluteCap or relativeCap | Keccak-256 of idData |
Read vault allocation | The same hashed ID |
| Allocate through this Blue adapter | ABI-encoded P |
The locked market-ID library hashes P's five words to obtain Blue's market ID. Hashing allocation data alone therefore produces that Blue ID. The adapter-plus-market cap ID also commits to a domain string and adapter address. The Blue market identity guide explains the underlying five-field market hash.
A cap setter accepts dynamic bytes, so a 32-byte digest can fit its argument type. The setter then hashes those 32 bytes again. An authorized operation can consequently target a different cap entry even though its transaction encoding is valid. Checking only that a transaction succeeded cannot establish that the intended cap changed.
Rebuild an illustrative ABI fixture
The following addresses are hypothetical patterns, chosen for reproducibility. Each address is 0x followed by exactly forty copies of its stated hexadecimal digit. No contract deployment, enabled market or actual token is asserted.
| Name | Repeated digit | Role |
|---|---|---|
| A | 1 | First adapter |
| B | 2 | Second adapter |
| L | a | Loan token |
| C | b | Collateral token |
| O | c | Oracle |
| I | d | Interest-rate model |
Set P to L, C, O, I and lltv 800000000000000000, in that order. The last value represents 80% with a 10^18 scale. Use standard ABI encoding and Keccak-256.
Inspect the words before hashing
Standard ABI encoding gives addresses and uint256 values 32-byte words. Dynamic strings have an offset in the head and a length-prefixed tail. A static tuple occupies its component words in place, as described by the Solidity ABI specification.
The adapter-wide preimage has four words, totaling 128 bytes. Word zero is integer 64, pointing to the string tail. Word one is A, left-padded with twelve zero bytes. Word two is integer 4, the string's byte length. Word three begins 74686973, the UTF-8 bytes for this, followed by 28 zero bytes.
The collateral preimage also has 128 bytes. Substitute C in word one. The string length becomes 15, and its UTF-8 content is collateralToken, padded to one word.
The market-cap preimage has nine words, totaling 288 bytes. Its first word is integer 224: the string tail follows seven head words. Those head words contain the offset, A and P's five fields. The last two words contain integer 17 and the padded UTF-8 string this/marketParams.
Allocation data has only P's five static words, totaling 160 bytes. These byte lengths provide an early diagnostic: a 160-byte candidate cannot be this adapter's market-cap preimage.
Compare the complete resulting keys
For each ID below, concatenate its four groups without spaces and prepend 0x. Each group has sixteen hexadecimal characters; together they form one bytes32 value.
- Adapter A:
e391f9b5e089841afff555cf1e817a1d8b1a6bc62440978ba3fae91e2eccbbb4. - Collateral C:
e0b16c976084a67102c2fb921a9b2c77ace3be68e9522038a2f61b6e609bcdc7. - Market P through A:
5bee7f3d7f3b3a26f9ed80d4ed413f673e0bc7355d40225a5a10ecc83341382f.
Changing only the adapter from A to B changes the adapter ID to one beginning 0xdc17035e and the market-cap ID to one beginning 0x4582a82e. The complete collateral ID stays identical. Compare full digests in a real check; the prefixes here identify the illustrative outputs.
The fixture was checked with installed viem 2.57.0 and an independent manual construction of every ABI word. Packed encoding of this and A instead has 24 bytes and hashes to a value beginning 0x927755b1. Standardized SHA3-256 also produces a different result. Neither substitutes for Keccak-256 over standard ABI bytes. Hash the decoded bytes represented by a hex value, rather than the UTF-8 characters of its printed hexadecimal text.
Follow the shared collateral cap across two adapters
Consider a separate illustrative allocation ledger using those two adapter addresses and market P. Let U be a fictional underlying loan token with six decimals. Assume both adapters are enabled, the allocator is authorized, P satisfies their configured requirements, and transfers and rounding produce exactly the stated allocation changes. There are no intervening gains, losses or other operations.
The vault has 2,000,000 U: A holds a 600,000 U position, B holds 300,000 U, and 1,100,000 U is idle. Every relevant relative cap is 100%, or 1e18, so this example isolates the absolute caps. The table uses displayed U; multiply by 1,000,000 for raw cap and allocation integers. Its final column models a 150,000 U addition through B.
| Risk key | Starting allocation | Absolute cap | Proposed ending allocation |
|---|---|---|---|
| Adapter A | 600,000 | 900,000 | 600,000 |
| Market P through A | 600,000 | 700,000 | 600,000 |
| Adapter B | 300,000 | 700,000 | 450,000 |
| Market P through B | 300,000 | 500,000 | 450,000 |
| Shared collateral C | 900,000 | 1,000,000 | 1,050,000 |
B's adapter and market keys pass their limits, but the common collateral key fails. The allocation loop checks every returned key, so the entire call reverts. Those proposed ending values are not committed balances. A fresh 100,000 U request from the original state fits: B reaches 400,000 U and the collateral bucket reaches exactly 1,000,000 U. Idle falls to 1,000,000 U; total assets stay at 2,000,000 U.
The usable headroom is the smallest relevant remainder: 400,000 U for B, 200,000 U for its market, and 100,000 U for the shared collateral. It is therefore 100,000 U under these assumptions. In raw units, the binding collateral cap is 1000000000000, its starting allocation is 900000000000, and the difference is 100000000000.
These are overlapping classifications of the same positions. Adding adapter, collateral and market allocations together would triple-count this ledger. The Yearn idle-versus-debt ledger illustrates a different kind of reconciliation, where two accounting categories partition the vault's total.
Validate the key and its actual coverage
Begin a real check with the chain, vault address, adapter address, implementation and observation block. Reconstruct P from exact addresses and the raw lltv integer. Obtain the named adapter's ids(P) output and compare every returned bytes32 value with the independently encoded hashes. Then read each allocation and both caps from the parent vault at the same block.
Preserve both raw idData and its digest in the working record. This lets a reviewer verify a setter proposal against the getters later used to confirm it. Cap changes have separate authority and timing rules; cap increases versus decreases follows that execution boundary. Absolute versus relative caps explains the additional fractional constraint after the identifiers match.
Inspect every other adapter before calling a collateral cap vault-wide coverage. The pinned MorphoVaultV1Adapter returns only its adapter ID. It does not report the Blue adapter's collateral key, so that common bucket does not automatically include its underlying collateral exposures. Identical keys in two separate vaults also belong to separate storage ledgers.
Finally, distinguish recorded allocation from current valuation and available cash. The Vault V2 implementation applies the adapter's reported change to every returned ID and checks caps during allocation. Stored allocations can lag gains and losses; relative caps are not enforced on exits. For a proposed allocation, simulate the complete call against current state and retain the confirmed parent-vault Allocate event and resulting cap reads. A correct digest identifies the risk bucket; the adapter's reporting and actual transaction determine what enters it.
