Skip to content

(De)List Markets

Market Listing

Overview of what listing a market means:

  1. Submit a cap for a given market
  2. Accept the cap (after timelock)
  3. Set the supply queue
  4. Optional but recommended: perform a small deposit

Submit the cap

Fill the arguments of the submitCap. On the addresses section of the documentation, you have the markets created on Morpho, let’s take as an example the market: WETH/wstETH (94.5%, ChainlinkOracle, AdaptiveCurveIRM).

Execute submitCap as in the picture below. Keep in mind that te newSupplyCap is in decimals of the asset (loan token).

Submit Cap.

Accept the cap

Wait for timelock to elapse and execute acceptCap()

Execute the acceptCap() with the market parameters of the market, which in this case are retrievable thanks to the idof the market: 0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41

Accept Cap.

Do this for as many markets as you expect the vault to deposit liquidity.

In the end, do not forget to submit and accept the cap for what we call the "idle" market.

The idle market is a Morpho market with the asset of the Morpho Vault as loanToken, the address(0) as the collateralToken, the address(0) as irm, the address(0) as oracle and 0 as lltv so that it is possible to supply on this market, but not to borrow. You might have to create a such market (with the createMarket function of the Morpho contract) if none of the already created markets of Morpho matches these parameters.

The cap for this market is supposed to be type(uint184).max, to always allow deposits into the vault.

Set the supplyQueue

Now one has to set the supplyQueue accordingly via the setSupplyQueue function, by giving as input a list of Ids of markets as follows:

[0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41,0x_MARKET_ID_2,...]

And execute with an address that has the onlyAllocatorRole:

  • Owner,
  • Curator,
  • Allocator.

Deposit liquidity

It is important to deposit a bit of liquidity (can be even 1$) such that the native rate of the vault is not 0 if the markets where liquidity flows is not 0. Any interface, scripts, or bots reading the market APYs will thus have a rate different than 0.

Market Delisting

Delisting a market from your MetaMorpho vault requires careful planning and execution. There are two levels of delisting:

  1. Basic delisting: Removing a market from the supply queue (while keeping it in the withdraw queue)
  2. Complete delisting: Removing a market from both supply and withdraw queues

This tutorial will guide you through both processes, focusing on best practices to ensure a smooth transition for all stakeholders.

Planning the Delisting Process

Before beginning the technical steps, consider the following:

  • Communicate with stakeholders about the planned delisting
  • Ensure there's sufficient liquidity in other markets to absorb reallocated funds
  • Plan a gradual transition to minimize market impact

Basic Delisting (Supply Queue Removal)

To stop new deposits from flowing to a specific market, you can remove it from the supply queue while keeping it in the withdraw queue. This approach allows existing positions to be maintained.

Execute setSupplyQueue with a new array that excludes the market you wish to delist.

For example, if your current supply queue is:

0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41; // 0: wstETH/WETH(94.5%)
0x3c83f77bde9541f8d3d82533b19bbc1f97eb2f1098bb991728acbfbede09cc5d; // 1: rETH/WETH(94.5%)
0x58e212060645d18eab6d9b2af3d56fbc906a92ff5667385f616f662c70372284; // 2: Idle Market - WETH

And you want to remove the wstETH/WETH market, you would call:

setSupplyQueue([0x3c83f77bde9541f8d3d82533b19bbc1f97eb2f1098bb991728acbfbede09cc5d,0x58e212060645d18eab6d9b2af3d56fbc906a92ff5667385f616f662c70372284])

This will prevent new deposits from being allocated to the removed market, but allows existing funds to remain there.

Reduce the Market Cap

To prepare for a complete delisting, you should first reduce the market cap to zero.

Execute submitCap with a value of 0 for the market you wish to delist.

input:
     [
         [ // marketParams tuple
         "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
         "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
         "0x2a01EB9496094dA03c4E364Def50f5aD1280AD72",
         "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
         "945000000000000000"
         ]
         ,0 // cap value, 0
     ]

Wait for the timelock to elapse and execute acceptCap() with the market parameters.

This step is necessary because a market with a non-zero cap cannot be removed from the withdraw queue.

Reallocate Liquidity

Before removing the market from the withdraw queue, you must withdraw all funds from it. Use the reallocate function to move funds from the market being delisted to other markets.

Execute reallocate with the appropriate market allocations.

Here's an example of how to reallocate all funds from a market being delisted to other markets:

[
  // First market to allocate funds to
  {
    "marketParams": {
      "loanToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
      "collateralToken": "0x3c83f77bde9541f8d3d82533b19bbc1f97eb2f1098bb991728acbfbede09cc5d",
      "oracle": "0x2a01EB9496094dA03c4E364Def50f5aD1280AD72",
      "irm": "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
      "lltv": "945000000000000000"
    },
    "assets": "TARGET_ASSET_AMOUNT" // Amount to allocate to this market
  },
  // Idle market (to catch any remaining assets)
  {
    "marketParams": {
      "loanToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
      "collateralToken": "0x0000000000000000000000000000000000000000",
      "oracle": "0x0000000000000000000000000000000000000000",
      "irm": "0x0000000000000000000000000000000000000000",
      "lltv": "0"
    },
    "assets": "115792089237316195423570985008687907853269984665640564039457584007913129639935" // Max value to catch all remaining assets
  }
]

Complete Delisting (Withdraw Queue Removal)

Once the market has a zero cap and no funds, you can remove it from the withdraw queue.

Execute updateWithdrawQueue with an array of indexes that excludes the market you wish to delist.

For example, if your current withdraw queue is:

0x58e212060645d18eab6d9b2af3d56fbc906a92ff5667385f616f662c70372284; // 0: Idle Market - WETH
0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41; // 1: wstETH/WETH(94.5%) - Market to remove
0x3c83f77bde9541f8d3d82533b19bbc1f97eb2f1098bb991728acbfbede09cc5d; // 2: rETH/WETH(94.5%)

And you want to remove the market at index 1 (wstETH/WETH), you would call:

updateWithdrawQueue([0,2])

This will keep the markets at index 0 and 2 in the new withdraw queue, and remove the market at index 1.

Emergency Market Removal

In exceptional cases where a market is malfunctioning (e.g., constantly reverting), you may need to force remove it.

Execute submitMarketRemoval with the market parameters of the market to remove.

input:
     [
         "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // loanToken
         "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", // collateralToken
         "0x2a01EB9496094dA03c4E364Def50f5aD1280AD72", // oracle
         "0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC", // irm
         "945000000000000000" // lltv
     ]

Wait for the timelock to elapse, then update the withdraw queue using updateWithdrawQueue as described in step 4.

Delisting Process Summary

For safe market delisting:

  1. Remove the market from the supply queue
  2. Reduce the market cap to zero
  3. Reallocate all funds from the market to other markets
  4. Remove the market from the withdraw queue

For emergency situations:

  1. Submit market removal
  2. Wait for timelock to elapse
  3. Update the withdraw queue

Always prioritize the safety of depositor funds and provide clear communication throughout the delisting process.