Manage exposure
Be sure to have read the previous section and that you are aware of the different functions behavior.
Set the Supply Queue
Let's consider that someone applied all steps from the previous section such that the supplyQueue
is thus composed of 3 market Ids:
0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41; // 0: wstETH/WETH(94.5%)
0x3c83f77bde9541f8d3d82533b19bbc1f97eb2f1098bb991728acbfbede09cc5d; // 1: rETH/WETH(94.5%)
0x58e212060645d18eab6d9b2af3d56fbc906a92ff5667385f616f662c70372284; // 2: Idle Market - WETH
One can verify it by putting 0, 1, 2, etc... numbers on the supplyQueue function on the vault itself.
To change the supplyQueue
, one can call the setSupplyQueue
with a new set of Id, by moving market 1 and 2 for instance:
0x3c83f77bde9541f8d3d82533b19bbc1f97eb2f1098bb991728acbfbede09cc5d; // 0: rETH/WETH(94.5%)
0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41; // 1: wstETH/WETH(94.5%)
0x58e212060645d18eab6d9b2af3d56fbc906a92ff5667385f616f662c70372284; // 2: Idle Market - WETH
And call the setSupplyQueue
function with the object:
setSupplyQueue([0x3c...523,0xc5...c41,0x58...284])
Then one can verify that this worked as expected by querying again the supplyQueue
function on the vault, one should see that the order changed.
Please keep in mind that it could be relevant to put the "idle" market as last element of the supplyQueue
.
Update the Withdraw Queue
Let's assume a vault has the following withdrawQueue
:
0x58e212060645d18eab6d9b2af3d56fbc906a92ff5667385f616f662c70372284; // 0: Idle Market - WETH
0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41; // 1: wstETH/WETH(94.5%)
0x3c83f77bde9541f8d3d82533b19bbc1f97eb2f1098bb991728acbfbede09cc5d; // 2: rETH/WETH(94.5%)
As a curator, if one wants to change the position of the last 2 markets:
-> call the function: updateWithdrawQueue
with: ["0","2","1"]
.
The new withdrawQueue
will be:
0x58e212060645d18eab6d9b2af3d56fbc906a92ff5667385f616f662c70372284; // 0: Idle Market - WETH
0x3c83f77bde9541f8d3d82533b19bbc1f97eb2f1098bb991728acbfbede09cc5d; // 1: rETH/WETH(94.5%)
0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41; // 2: wstETH/WETH(94.5%)
Please keep in mind that it could be relevant to put the "idle" market as first element of the withdrawQueue
.
Remove a market
To force remove a market, one can call submitMarketRemoval
.
Warning
- Submits a forced market removal from the vault, eventually losing all funds supplied to the market.
- Note that funds can be recovered by enabling this market again and withdrawing from it (using
reallocate
), but funds will be distributed pro-rata to the shares at the time of withdrawal, not at the time of removal. - This forced removal is expected to be used as an emergency process in case a market constantly reverts.
- To softly remove a sane market, the curator role is expected to bundle a reallocation that empties the market first (using
reallocate
), followed by the removal of the market (usingupdateWithdrawQueue
). - Reverts for non-zero cap or if there is a pending cap. Successfully submitting a zero cap wil prevent such reverts.
Let's assume a vault has the following withdrawQueue
:
0x58e212060645d18eab6d9b2af3d56fbc906a92ff5667385f616f662c70372284; // 0: Idle Market - WETH
0x3c83f77bde9541f8d3d82533b19bbc1f97eb2f1098bb991728acbfbede09cc5d; // 1: rETH/WETH(94.5%)
0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41; // 2: wstETH/WETH(94.5%)
As a curator, if one wants to remove the last market, one can call the function: submitMarketRemoval
with the marketParams
of the market Id: 0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41
. Here are the following steps that need to be done:
1. Retrieve the marketParams
data
Jump into the Morpho contract, and in the read functions section, call the idToMarketParams
function with the market Id you are expecting to remove as input:
input:
"0xc54d7acf14de29e0e5527cabd7a576506870346a78a11a6762e2cca66322ec41"; // wstETH/WETH(94.5%)
output:
"loanToken":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"collateralToken":"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
"oracle":"0x2a01EB9496094dA03c4E364Def50f5aD1280AD72",
"irm":"0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
"lltv":"945000000000000000"
The value retrieved are the market parameters (marketParams
) of the market you want to remove.
2. Send submitCap
transaction
As the curator, send a submitCap
transaction with a cap of 0 to the market you want to remove.
a. The marketParams
one is expecting to remove, retrieved in 1.
b. The cap value, which has to be set to 0.
input:
[
[ // marketParams tuple
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
"0x2a01EB9496094dA03c4E364Def50f5aD1280AD72",
"0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
"945000000000000000"
]
,0 // cap value, 0
]
3. Send submitMarketRemoval
transaction
Paste again the marketParams
retrieved in 1, and call the submitMarketRemoval
function with those parameters:
[
"loanToken":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"collateralToken":"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
"oracle":"0x2a01EB9496094dA03c4E364Def50f5aD1280AD72",
"irm":"0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC",
"lltv":"945000000000000000"
]
4. Send an updateWithdrawQueue
transaction
One wants to keep only the market of the withdrawQueue
that are in position 0 and position 2 as per the example:
After timelock (otherwise, the transaction will revert), put [0,2] in the updateWithdrawQueue
function.
This is it, one can verify in the withdrawQueue
that there no longer is the market that was removed.
Reallocation examples
Prerequisites
Any address that has the onlyAllocatorRole
will be able to execute the reallocate
function which reallocates the vault's liquidity to reach a given allocation of assets on each specified market.
The allocator can withdraw from any market, even if it's not in the withdraw queue, as long as the loan token of the market is the same as the vault's asset.
Be sure to have read the technical reference definition of the reallocate function before proceeding.
The function takes into input the MarketAllocation[]
, with MarketAllocation
implemented like this:
struct MarketAllocation {
MarketParams marketParams;
uint256 assets;
}:
and MarketParams implemented like this:
struct MarketParams {
address loanToken;
address collateralToken;
address oracle;
address irm;
uint256 lltv;
}
The assets
field represents the amount of liquidity you want to allocate to that specific market after the reallocation. It essentially defines the targeted state of your allocation.
Steps to Execute a Reallocation
-
Identify the Target State: Determine how much of the vault's liquidity you want to allocate to each market. The total of these allocations should match the total liquidity available in the vault if you want to fully utilize the available funds.
-
Prepare the MarketAllocations Array: For each market, create a MarketAllocation object with the appropriate parameters and the target amount of liquidity (assets) you want to allocate to that market.
-
Execute the Reallocation: Call the reallocate function with the prepared MarketAllocations array.
Example
Here is an example of how to structure the MarketAllocation[] input for the reallocate function:
[
{
"marketParams": {
"loanToken": "0xLOAN_TOKEN_ADDRESS", // Address of the loan token
"collateralToken": "0xCOLLATERAL_TOKEN_ADDRESS", // Address of the collateral token
"oracle": "0xORACLE_ADDRESS", // Address of the oracle
"irm": "0xIRM_ADDRESS", // Address of the interest rate model
"lltv": "900000000000000000" // Loan-to-Value ratio, for example, 90% (18 decimals precision)
},
"assets": "TARGET_ASSET_AMOUNT" // Amount of assets to allocate
},
{
"marketParams": {
"loanToken": "0xLOAN_TOKEN_ADDRESS", // Address of the loan token
"collateralToken": "0xCOLLATERAL_TOKEN_ADDRESS", // Address of the collateral token
"oracle": "0xORACLE_ADDRESS", // Address of the oracle
"irm": "0xIRM_ADDRESS", // Address of the interest rate model
"lltv": "900000000000000000" // Loan-to-Value ratio, for example, 90% (18 decimals precision)
},
"assets": "TARGET_ASSET_AMOUNT" // Amount of assets to allocate
},
{
"marketParams": {
"loanToken": "0xLOAN_TOKEN_ADDRESS", // Address of the loan token
"collateralToken": "0x0000000000000000000000000000000000000000", // Use zero address for idle markets
"oracle": "0x0000000000000000000000000000000000000000", // Use zero address for idle markets
"irm": "0x0000000000000000000000000000000000000000", // Use zero address for idle markets
"lltv": "0"
},
"assets": "115792089237316195423570985008687907853269984665640564039457584007913129639935" // Max value to ensure all remaining assets are allocated
}
]
- To ensure that the total withdrawn amount equals the total supplied amount, the sender is expected to pass:
assets = type(uint256).max
in the lastMarketAllocation
ofallocations
. This guarantees that all the remaining withdrawn liquidity is supplied, ensuringtotalWithdrawn
=totalSupplied
. - If you expect a market to be empty, just remove it from the
MarketAllocation[]
array.