Skip to content

Manage 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 external yield protocol. As a Curator, enabling and managing adapters is how you define your vault's investment universe.

This guide will walk you through the process of deploying, listing, and managing adapters, with a focus on two key adapters:

  1. MorphoVaultV1Adapter: Connects your Vault V2 to a Morpho Vault V1 (MetaMorpho).
  2. MorphoMarketV1Adapter: Connects your Vault V2 directly to Morpho Blue markets.

Setting Up Your First Adapter: The MorphoVaultV1Adapter

A common and powerful strategy is to use a Vault V2 as a "wrapper" around an existing Morpho Vault V1. This is automatically handled by the deployment script.

Method 1: Setting an Adapter via Script (Recommended)

The official deployment repository handles adapter setup automatically: https://github.com/morpho-org/vault-v2-deployment

The DeployVaultV2.s.sol script includes:

// Deploy MorphoVaultV1Adapter
address morphoVaultV1Adapter = address(new MorphoVaultV1Adapter(address(vaultV2), address(vaultV1)));
 
// Submit and execute adapter enablement
bytes memory idData = abi.encode("this", morphoVaultV1Adapter);
vaultV2.submit(abi.encodeCall(vaultV2.setIsAdapter, (morphoVaultV1Adapter, true)));
vaultV2.setIsAdapter(morphoVaultV1Adapter, true);
 
// Set caps for the adapter
vaultV2.submit(abi.encodeCall(vaultV2.increaseAbsoluteCap, (idData, type(uint128).max)));
vaultV2.submit(abi.encodeCall(vaultV2.increaseRelativeCap, (idData, 1e18)));
vaultV2.increaseAbsoluteCap(idData, type(uint128).max);
vaultV2.increaseRelativeCap(idData, 1e18);
 
// Set as liquidity adapter
vaultV2.setLiquidityAdapterAndData(morphoVaultV1Adapter, bytes(""));

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 {MorphoVaultV1Adapter} from "vault-v2/adapters/MorphoVaultV1Adapter.sol";
import {MorphoMarketV1Adapter} from "vault-v2/adapters/MorphoMarketV1Adapter.sol";
 
contract AddAdapter is Script {
    function run() external {
        address vaultAddress = vm.envAddress("VAULT_V2_ADDRESS");
        address targetVaultV1 = vm.envAddress("TARGET_VAULT_V1");
        
        IVaultV2 vault = IVaultV2(vaultAddress);
        
        vm.startBroadcast();
        
        // Deploy new adapter
        address newAdapter = address(new MorphoVaultV1Adapter(vaultAddress, targetVaultV1));
        
        // Submit enablement proposal
        bytes memory enableData = abi.encodeCall(IVaultV2.setIsAdapter, (newAdapter, true));
        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 2: Setting an Adapter via Etherscan

1. Deploy the Adapter

For MorphoVaultV1Adapter:

  1. Deploy the contract with constructor parameters:
    • _parentVault: Your Vault V2 address
    • _morphoVaultV1: Target Vault V1 address

For MorphoMarketV1Adapter:

  1. Deploy with:
    • _parentVault: Your Vault V2 address
    • _morpho: Morpho Blue contract address

2. Enable the Adapter

  1. As Curator, encode: abi.encodeCall(IVaultV2.setIsAdapter, (adapterAddress, true)).
  2. Call submit(bytes) with the encoded data.
  3. After timelock, call setIsAdapter(adapterAddress, true).

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:

setLiquidityAdapterAndData(adapterAddress, bytes(""))

Working with MorphoMarketV1Adapter

When allocating to Morpho Blue markets directly:

// Prepare market parameters
MarketParams memory marketParams = MarketParams({
    loanToken: loanTokenAddress,
    collateralToken: collateralTokenAddress,
    oracle: oracleAddress,
    irm: irmAddress,
    lltv: lltv
});
 
// Allocate as Allocator
bytes memory data = abi.encode(marketParams);
vault.allocate(morphoMarketV1Adapter, data, amount);

Managing Adapter Caps

Each adapter has associated IDs for risk management:

  • MorphoVaultV1Adapter: Single ID based on keccak256(abi.encode("this", adapterAddress))
  • MorphoMarketV1Adapter: Three IDs:
    • Adapter ID: keccak256(abi.encode("this", adapterAddress))
    • Collateral ID: keccak256(abi.encode("collateralToken", collateralAddress))
    • Market ID: keccak256(abi.encode("this/marketParams", adapterAddress, marketParams))

Sentinels can decrease caps immediately:

vault.decreaseAbsoluteCap(idData, newLowerCap);
vault.decreaseRelativeCap(idData, newLowerRelativeCap);

Delisting an Adapter

To delist:

  1. Deallocate All Funds:
vault.deallocate(adapterAddress, data, totalAllocated);
  1. Submit Delisting Proposal (as Curator):
bytes memory data = abi.encodeCall(IVaultV2.setIsAdapter, (adapterAddress, false));
vault.submit(data);
  1. Execute After Timelock:
vault.setIsAdapter(adapterAddress, false);

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