Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Create a Morpho Vault V2

Deploying a Morpho Vault V2 is a permissionless process that anyone can initiate. This guide covers three methods for deploying your vault, ranging from the simplest user-friendly interface to more advanced technical approaches.

This guide covers three methods for deploying your vault:

  1. Using the Curator App (Recommended): The easiest and most user-friendly method with a graphical interface for vault creation and configuration.
  2. Using a Deployment Script: A powerful and efficient method for developers, allowing you to create, configure, and assign roles for your vault in a single, automated process.
  3. Using Etherscan: A manual approach suitable for those who prefer interacting directly with contracts on a block explorer.

Method 1: Create a Vault via the Curator App

The Curator App provides the easiest and most user-friendly way to deploy a Morpho Vault V2. This web-based interface guides you through the entire vault creation process without requiring any coding or command-line experience.

Curator App: https://curator.morpho.org/vaults

Why Use the Curator App?

  • No Technical Knowledge Required: User-friendly graphical interface suitable for all experience levels.
  • Guided Setup: Step-by-step wizard walks you through every configuration option.
  • Instant Deployment: Deploy your vault directly from your browser using your connected wallet.
  • Built-in Validation: Automatic validation of parameters to prevent common configuration mistakes.
  • Visual Configuration: Easily configure roles, adapters, and risk parameters through intuitive forms.

Getting Started with the Curator App

1. Connect Your Wallet

Navigate to https://curator.morpho.org/vaults and connect your Ethereum wallet (e.g., MetaMask, WalletConnect).

2. Select Network

Choose the network where you want to deploy your vault. Morpho Vault V2 is available on multiple networks including Ethereum mainnet, Base, and other supported chains.

3. Configure Vault Parameters

You will first be asked to set the main vault's parameters:

  • Asset: Select the ERC-20 token your vault will use (e.g., USDC, WETH).
  • Owner: Set the initial owner address (ideally a multisig for security).

Once the vault created, set and abdicate the Morpho registry.

You can then set the other Vault's parameters:

  • Vault Symbol: Choose a token symbol for your vault.
  • Vault Name: Choose a descriptive name for your vault.
  • Curator: Assign the curator role for managing vault parameters.
  • Allocator: Set the allocator address for managing fund allocations.
  • Sentinel (Optional): Optionally assign a sentinel for emergency actions.
  • MaxRate: The maximum rate earn by vault's suppliers. MaxRate must be set for suppliers to earn yield (more here).

4. Configure Adapters and Risk Parameters

  • Select which Morpho Vault V1 instances you want to use as underlying liquidity markets.
  • Set initial risk caps (absolute and relative) for each adapter.
  • Configure the liquidity adapter for managing fund flows.

5. Set Timelock (Optional)

Configure timelock durations for critical functions to add an additional security layer for production vaults.

6. Review and Deploy

Review all your configuration settings, then click "Deploy Vault". Your wallet will prompt you to confirm the transaction.

Once deployed, you can continue managing your vault through the Curator App or use the advanced methods described below for programmatic management.

Method 2: Create and Configure a Morpho Vault V2 via Script

For developers who prefer a code-based approach, you can refer to the Morpho Vault V2 deployment repository. This repository contains an example script that bundles multiple setup actions into a single transaction.

Repository: https://github.com/morpho-org/vault-v2-deployment

Overview

The DeployVaultV2WithMarketAdapter.s.sol script demonstrates how to deploy and configure a Morpho Vault V2. It leverages the fact that new vaults have a zero-second timelock by default, allowing all initial configuration to be executed immediately.

This script deploys a Morpho Vault V2 using MorphoMarketV1AdapterV2, which connects directly to Morpho Markets V1.

The deployment process consists of the following phases:

PhaseDescription
1Deploy Morpho Vault V2 instance via factory
2Configure temporary permissions
3Deploy MorphoMarketV1AdapterV2
4Submit timelocked configuration changes
5Execute configuration + gates abdication
6Set final role assignments
7Configure market and liquidity adapter
8Execute vault dead deposit
9Configure vault timelocks
10Configure adapter timelocks

Prerequisites

Before deploying, ensure you have:

  • Foundry installed
  • Git installed
  • An Ethereum wallet with sufficient funds for deployment
  • RPC URL for your target network
  • Sufficient tokens for the dead deposit (required for inflation attack protection)

Running the Deployment Script

1. Clone the Repository and Install Dependencies

git clone https://github.com/morpho-org/vault-v2-deployment
cd vault-v2-deployment
forge install

2. Configure Environment Variables

Create a .env file with your deployment configuration:

# Network
RPC_URL=https://...            # Your RPC endpoint
PRIVATE_KEY=0x...              # Your private key (keep secure!)
 
# Role addresses (replace with your actual addresses)
OWNER=0x...                    # Final owner of the vault (ideally a multisig)
CURATOR=0x...                  # Curator address (defaults to OWNER if not set)
ALLOCATOR=0x...                # Allocator address (defaults to OWNER if not set)
SENTINEL=0x...                 # Sentinel address (optional)
 
# Deployed contract addresses (network-specific)
# See https://docs.morpho.org/get-started/resources/addresses/ for addresses
ASSET=0x...                    # Underlying asset token (e.g., USDC, WETH)
ADAPTER_REGISTRY=0x...         # Morpho Registry address
VAULT_V2_FACTORY=0x...         # VaultV2 Factory address
MORPHO_MARKET_V1_ADAPTER_V2_FACTORY=0x...  # MorphoMarketV1AdapterV2 Factory address
 
# First market configuration (optional - set to 0x0 to skip)
MARKET_ID=0x...                # Morpho Blue market ID
COLLATERAL_TOKEN_CAP=...       # Max allocation to collateral token
MARKET_CAP=...                 # Max allocation to specific market
 
# Timelock configuration (in seconds)
# Good practice is a minimum 3 days = 259200 seconds
VAULT_TIMELOCK_DURATION=259200
ADAPTER_TIMELOCK_DURATION=259200
 
# Optional: For contract verification
ETHERSCAN_API_KEY=...          # Your Etherscan API key

3. Simulate the Deployment

First, simulate the deployment to verify everything works:

source .env && forge script script/DeployVaultV2WithMarketAdapter.s.sol \
  --fork-url "$RPC_URL" \
  --private-key "$PRIVATE_KEY" \
  -vvv

In simulation mode (without --broadcast), the script will complete all deployment phases and gracefully skip the dead deposit if the deployer has no tokens.

4. Deploy the Morpho Vault V2

Run the deployment script with --broadcast to execute on-chain:

# Without block explorer verification
forge script script/DeployVaultV2WithMarketAdapter.s.sol \
  --rpc-url $RPC_URL \
  --private-key $PRIVATE_KEY \
  --broadcast

Or with verification on Etherscan:

# With verification on Etherscan
forge script script/DeployVaultV2WithMarketAdapter.s.sol \
  --rpc-url $RPC_URL \
  --private-key $PRIVATE_KEY \
  --broadcast \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --verify

The script will output the addresses of all deployed contracts and confirm each configuration step.

Testing Before Mainnet Deployment

The repository includes testing tools to help you validate your deployment:

# Run all tests on fork
source .env && forge test --fork-url "$RPC_URL" -vvv
 
# Run specific test
forge test --match-test test_FullDeploymentWithTimelocks -vvv

Important: Always test your deployment configuration on a testnet before deploying to mainnet.

Good practices

The script addresses the following good practices:

Good practicesHow Script Addresses It
Non-custodial GatesPhase 5: Gates abdicated (cannot be re-enabled)
No Idle LiquidityPhase 7: liquidityAdapter allocates deposits to market
Dead DepositPhase 8: 1e9-1e12 wei deposited on behalf of 0xdead
Vault TimelocksPhase 9: Configures timelocks for vault functions (>= 3 days)
Adapter TimelocksPhase 10: Configures adapter timelocks (burnShares >= 3 days)
Naming RestrictionManual check: Name/symbol cannot contain "morpho"

Understanding the Deployment Steps

The DeployVaultV2WithMarketAdapter.s.sol script orchestrates a comprehensive deployment process. Here's what happens internally:

Phase 1: Deploy Morpho Vault V2 Instance

// Deploy Morpho Vault V2 using the factory
bytes32 uniqueSalt = keccak256(abi.encodePacked(block.timestamp + gasleft()));
VaultV2 deployedVaultV2 = VaultV2(
    VaultV2Factory(factoryAddress).createVaultV2(
        temporaryOwner,
        underlyingAsset,
        uniqueSalt
    )
);

Phase 2: Configure Temporary Permissions

// Set broadcaster as temporary curator for configuration
vault.setCurator(temporaryCurator);

Phase 3: Deploy MorphoMarketV1AdapterV2

// Deploy MorphoMarketV1AdapterV2 using the adapter factory
IMorphoMarketV1AdapterV2Factory factory = IMorphoMarketV1AdapterV2Factory(factoryAddress);
address adapterAddress = factory.createMorphoMarketV1AdapterV2(vaultV2Address);

Phase 4: Submit Timelocked Configuration Changes

// Submit all configuration changes that will be timelocked
vault.submit(abi.encodeCall(vault.setIsAllocator, (allocator, true)));
vault.submit(abi.encodeCall(vault.setAdapterRegistry, (registry)));
 
bytes memory adapterIdData = abi.encode("this", adapter);
vault.submit(abi.encodeCall(vault.addAdapter, (adapter)));
vault.submit(abi.encodeCall(vault.increaseAbsoluteCap, (adapterIdData, type(uint128).max)));
vault.submit(abi.encodeCall(vault.increaseRelativeCap, (adapterIdData, 1e18)));
 
// Submit abdication for registry and gates (non-custodial requirement)
vault.submit(abi.encodeCall(vault.abdicate, (IVaultV2.setAdapterRegistry.selector)));
vault.submit(abi.encodeCall(vault.abdicate, (IVaultV2.setReceiveSharesGate.selector)));
vault.submit(abi.encodeCall(vault.abdicate, (IVaultV2.setSendSharesGate.selector)));
vault.submit(abi.encodeCall(vault.abdicate, (IVaultV2.setReceiveAssetsGate.selector)));

Phase 5: Execute Configuration and Gates Abdication

// Since timelock is 0 initially, execute configurations immediately
vault.setAdapterRegistry(registry);
vault.setIsAllocator(allocator, true);
vault.addAdapter(adapter);
 
bytes memory adapterIdData = abi.encode("this", adapter);
vault.increaseAbsoluteCap(adapterIdData, type(uint128).max);
vault.increaseRelativeCap(adapterIdData, 1e18);
 
// Abdicate registry and gates (preserves non-custodial properties)
vault.abdicate(IVaultV2.setAdapterRegistry.selector);
vault.abdicate(IVaultV2.setReceiveSharesGate.selector);
vault.abdicate(IVaultV2.setSendSharesGate.selector);
vault.abdicate(IVaultV2.setReceiveAssetsGate.selector);

Phase 6: Set Final Role Assignments

// Assign final roles to production addresses
vault.setCurator(vaultCurator);
 
if (vaultSentinel != address(0)) {
    vault.setIsSentinel(vaultSentinel, true);
}
 
vault.setOwner(vaultOwner);

Phase 7: Configure Market and Liquidity Adapter

// Look up MarketParams from Morpho and set liquidity adapter
MarketParams memory marketParams = IMorpho(morpho).idToMarketParams(Id.wrap(marketId));
bytes memory liquidityData = abi.encode(marketParams);
vault.setLiquidityAdapterAndData(address(adapter), liquidityData);
 
// Configure collateral token and market caps
bytes memory collateralTokenIdData = abi.encode("collateralToken", marketParams.collateralToken);
vault.increaseAbsoluteCap(collateralTokenIdData, collateralTokenCap);
vault.increaseRelativeCap(collateralTokenIdData, 1e18);
 
bytes memory marketIdData = abi.encode("this/marketParams", address(adapter), marketParams);
vault.increaseAbsoluteCap(marketIdData, marketCap);
vault.increaseRelativeCap(marketIdData, 1e18);

Phase 8: Execute Dead Deposit

// Seed vault with initial liquidity to prevent inflation attacks
// Amount depends on asset decimals: 1e9 for >= 10 decimals, 1e12 for <= 9 decimals
IERC20(vault.asset()).approve(address(vault), depositAmount);
vault.deposit(depositAmount, address(0xdead)); // Burned shares

Phase 9: Configure Vault Timelocks

// Configure timelocks for vault functions (good practices: >= 3 days)
bytes4[] memory selectors = new bytes4[](7);
selectors[0] = IVaultV2.addAdapter.selector;
selectors[1] = IVaultV2.increaseAbsoluteCap.selector;
selectors[2] = IVaultV2.increaseRelativeCap.selector;
selectors[3] = IVaultV2.setForceDeallocatePenalty.selector;
selectors[4] = IVaultV2.abdicate.selector;
selectors[5] = IVaultV2.removeAdapter.selector;
selectors[6] = IVaultV2.increaseTimelock.selector; // MUST BE LAST!
 
for (uint256 i = 0; i < selectors.length; i++) {
    vault.submit(abi.encodeCall(vault.increaseTimelock, (selectors[i], timelockDuration)));
    vault.increaseTimelock(selectors[i], timelockDuration);
}

Phase 10: Configure Adapter Timelocks

// Configure timelocks for adapter functions (good practices: burnShares >= 3 days)
bytes4[] memory selectors = new bytes4[](4);
selectors[0] = IMorphoMarketV1AdapterV2.abdicate.selector;
selectors[1] = IMorphoMarketV1AdapterV2.setSkimRecipient.selector;
selectors[2] = IMorphoMarketV1AdapterV2.burnShares.selector;
selectors[3] = IMorphoMarketV1AdapterV2.increaseTimelock.selector; // MUST BE LAST!
 
for (uint256 i = 0; i < selectors.length; i++) {
    adapter.submit(abi.encodeCall(adapter.increaseTimelock, (selectors[i], timelockDuration)));
    adapter.increaseTimelock(selectors[i], timelockDuration);
}

Method 3: Create a Vault Manually via Etherscan

If you prefer a manual approach without using the Curator App or deployment scripts, you can deploy a vault directly by interacting with the contracts on a block explorer like Etherscan.

Prerequisites

  • An Ethereum wallet (e.g., MetaMask) connected to the desired network.
  • The address of the ERC-20 token the vault will use as its asset.
  • The address you want to designate as the initial owner.

Step-by-Step Guide

1. Deploy a New VaultV2 Contract

Since Vault V2 doesn't use a factory pattern, you'll need to deploy the contract directly. This typically requires using a development environment like Remix or Foundry.

For Remix:

  1. Copy the VaultV2.sol contract and its dependencies.
  2. Compile with Solidity 0.8.28.
  3. Deploy with constructor parameters:
    • _owner: The initial owner address (ideally your multisig).
    • _asset: The ERC-20 token address (e.g., USDC, WETH).

2. Verify the Contract

After deployment, verify the contract on Etherscan to enable the Write Contract interface.

3. Configure the Vault

Once deployed and verified, you'll need to:

  1. Set up roles (see Manage Vault V2 Roles).
  2. Deploy and configure adapters (see (De)List Adapters).

Congratulations! Your vault is now deployed. For a production-ready setup, we strongly recommend using the deployment script method as it ensures all components are properly configured.