Curate Adapters (Vaults V2)
Adapters are the core of a Morpho Vault V2's extensibility. They are smart contracts that act as bridges, allowing your vault to connect to and allocate assets in any version of the Morpho protocol. As a Curator, enabling and configuring adapters is how you define your vault's allocation universe.
This guide will walk you through the process of deploying, listing, and configuring adapters, with a focus on the MorphoMarketV1AdapterV2 that connects your Morpho Vault V2 directly to Morpho Variable Rate Markets. It also covers configuring adapter caps after deployment.
What is an Adapter?
An adapter contains the specific logic needed to allocate and deallocate assets to a target protocol. It must be enabled via addAdapter (a timelocked action) before the vault can interact with it. Adapters also define the "ids" used for risk management caps.
Setting Up the MorphoMarketV1AdapterV2
The MorphoMarketV1AdapterV2 allows your Morpho Vault V2 to allocate directly to variable rate markets. It is deployed via the MorphoMarketV1AdapterV2Factory, which takes the parent vault address and automatically connects to the Morpho Blue contract.
Method 1: via the Curator App V2 (Recommended)
On your Morpho Vault V2 page, navigate to the Adapters tab. If no adapter is configured yet, the interface will guide you through the setup flow.
The flow will implement the steps below:
- Deploy adapter
- Submit adapter
- Approve adapter timelock (if any)
- Set adapter caps
Before allocating, configure the required collateral-token and market caps in (De)List Markets.
Method 2: via Script
The deployment repository handles adapter setup automatically: https://github.com/morpho-org/vault-v2-deployment
This repository is for educational purposes only. Do not use in production without thorough review and testing.
For adding adapters after deployment:
script/AddAdapter.s.sol
pragma solidity 0.8.28;
import {Script, console} from "forge-std/Script.sol";
import {IVaultV2} from "vault-v2/interfaces/IVaultV2.sol";
import {IMorphoMarketV1AdapterV2Factory} from "vault-v2/adapters/interfaces/IMorphoMarketV1AdapterV2Factory.sol";
contract AddAdapter is Script {
function run() external {
address vaultAddress = vm.envAddress("VAULT_V2_ADDRESS");
address factoryAddress = vm.envAddress("MORPHO_MARKET_V1_ADAPTER_V2_FACTORY");
IVaultV2 vault = IVaultV2(vaultAddress);
vm.startBroadcast();
// Deploy new adapter via factory
address newAdapter = IMorphoMarketV1AdapterV2Factory(factoryAddress)
.createMorphoMarketV1AdapterV2(vaultAddress);
// Submit enablement proposal
bytes memory enableData = abi.encodeCall(IVaultV2.addAdapter, (newAdapter));
vault.submit(enableData);
// Submit cap increases
bytes memory idData = abi.encode("this", newAdapter);
vault.submit(abi.encodeCall(IVaultV2.increaseAbsoluteCap, (idData, type(uint128).max)));
vault.submit(abi.encodeCall(IVaultV2.increaseRelativeCap, (idData, 1e18)));
vm.stopBroadcast();
console.log("Adapter deployed at:", newAdapter);
console.log("Proposals submitted. Execute after timelock.");
}
}Method 3: via Etherscan
1. Deploy the Adapter
Deploy MorphoMarketV1AdapterV2 via its factory by calling:
factory.createMorphoMarketV1AdapterV2(vaultV2Address)where factory is the deployed MorphoMarketV1AdapterV2Factory contract.
2. Enable the Adapter
- As Curator, encode:
abi.encodeCall(IVaultV2.addAdapter, (adapterAddress)). - Call
submit(bytes)with the encoded data. - After timelock, call
addAdapter(adapterAddress).
3. Set Risk Caps
The adapter's ID is computed as:
bytes memory idData = abi.encode("this", adapterAddress);
bytes32 id = keccak256(idData);Submit and execute cap increases:
increaseAbsoluteCap(idData, capAmount)increaseRelativeCap(idData, relativeCapWad)(where 1e18 = 100%)
4. Set as Liquidity Adapter (if needed)
As Allocator, call with the default MarketParams encoded as data. The encoded market params identify which Morpho Variable Rate Market will receive new user deposits and serve withdrawals:
bytes memory liquidityData = abi.encode(marketParams);
vault.setLiquidityAdapterAndData(adapterAddress, liquidityData);Configuring Adapter Caps
Method 1: via the Curator App V2 (Recommended)
Directly on the Caps page of your Morpho Vault V2 by clicking on the "Edit Caps" button.
Cap increases with a non-zero timelock are submitted as pending actions. Once the timelock has elapsed, execute them from the vault's Timelocks page. If the timelock is zero, the Curator App submits and executes the cap changes in the same transaction. Cap decreases take effect immediately.
Method 2: via Script
Each adapter has associated IDs for risk management:
- MorphoMarketV1AdapterV2: Three IDs:
- Adapter ID:
keccak256(abi.encode("this", adapterAddress)) - Collateral ID:
keccak256(abi.encode("collateralToken", collateralAddress)) - Market ID:
keccak256(abi.encode("this/marketParams", address(this), marketParams))- whereaddress(this)is the deployed adapter address
- Adapter ID:
- MorphoVaultV1Adapter: Single ID based on
keccak256(abi.encode("this", adapterAddress))
Sentinels can decrease caps immediately:
vault.decreaseAbsoluteCap(idData, newLowerCap);
vault.decreaseRelativeCap(idData, newLowerRelativeCap);Delisting an Adapter
Critical: Set Caps to Zero Before Removing an Adapter
Before delisting an adapter, you must set both the absolute cap and relative cap to 0
for every ID exclusive to that adapter. This prevents any allocator from frontrunning the
timelocked removeAdapter call by allocating assets into the adapter during the timelock
window. Without this step, an allocator could push assets into the adapter right before
removal, and since removeAdapter does not revert if the adapter still holds assets,
those assets would be permanently lost to the vault's depositors.
Before delisting, follow the full Adapter Soft Deprecation procedure, which covers both deallocating existing assets and zeroing caps to prevent frontrunning.
Setting Force Deallocate Penalty
To enable emergency withdrawals with a penalty:
// As Curator, submit proposal (max 2% = 0.02e18)
vault.submit(abi.encodeCall(IVaultV2.setForceDeallocatePenalty, (adapterAddress, 0.01e18)));
// After timelock
vault.setForceDeallocatePenalty(adapterAddress, 0.01e18); // 1% penalty