Inherits: ERC4626, Multicall, AccessControlDefaultAdminRules, ReentrancyGuard
Author: Molecular Labs
Vault contract that can allocate a single lender asset over various isolated lending pairs on Ion Protocol. This contract is a fork of the Metamorpho contract licnesed under GPL-2.0 with changes to administrative logic, underlying data structures, and lending interactions to be made compatible with Ion Protocol.
Updates the fee percentage.
Input must be in [RAY]. Ex) 2% would be 0.02e27.
Parameters
_feePercentage
uint256
The percentage of the interest accrued to take as a management fee.
Updates the fee recipient.
Parameters
_feeRecipient
address
The recipient address of the shares minted as fees.
Add markets that can be supplied and withdrawn from.
Elements in supportedMarkets
must be a valid IonPool or an IDLE address. Valid IonPools require the base asset to be the same. Duplicate addition to the EnumerableSet will revert. The allocationCaps of the new markets being introduced must be set.
Parameters
marketsToAdd
IIonPool[]
Array of new markets to be added.
allocationCaps
uint256[]
Array of allocation caps for only the markets to be added.
newSupplyQueue
IIonPool[]
Desired supply queue of IonPools for all resulting supported markets.
newWithdrawQueue
IIonPool[]
Desired withdraw queue of IonPools for all resulting supported markets.
Removes a supported market and updates the supply and withdraw queues without the removed market.
The allocationCap values of the markets being removed are automatically deleted. Whenever a market is removed, the queues must be updated without the removed market.
Parameters
marketsToRemove
IIonPool[]
Markets being removed.
newSupplyQueue
IIonPool[]
Desired supply queue of all supported markets after the removal.
newWithdrawQueue
IIonPool[]
Desired withdraw queue of all supported markets after the removal.
Update the order of the markets in which user deposits are supplied.
Each IonPool in the queue must be part of the supportedMarkets
set.
Parameters
newSupplyQueue
IIonPool[]
The new supply queue ordering.
Update the order of the markets in which the deposits are withdrawn.
The IonPool in the queue must be part of the supportedMarkets
set.
Parameters
newWithdrawQueue
IIonPool[]
The new withdraw queue ordering.
*The input array contains ordered IonPools.
Must not contain duplicates.
Must be the same length as the supportedMarkets
array.
Must not contain indices that are out of bounds of the supportedMarkets
EnumerableSet's underlying array. The above rule enforces that the queue must have all and only the elements in the supportedMarkets
set.*
Parameters
queue
IIonPool[]
The queue being validated.
Update allocation caps for specified IonPools or the IDLE pool.
The allocation caps are applied to pools in the order of the array within supportedMarkets
. The elements inside ionPools
must exist in supportedMarkets
. To update the IDLE
pool, use the IDLE
constant address.
Parameters
ionPools
IIonPool[]
The array of IonPools whose caps will be updated.
newCaps
uint256[]
The array of new allocation caps to be applied.
Reallocates the base asset supply position across the specified IonPools. This call will revert if the resulting allocation in an IonPool violates the pool's supply cap.
*Depending on the order of deposits and withdrawals to and from markets, the function could revert if there is not enough assets withdrawn to deposit later in the loop. A key invariant is that the total assets withdrawn should be equal to the total assets supplied. Otherwise, revert.
Negative value indicates a withdrawal.
Positive value indicates a supply.*
Parameters
allocations
MarketAllocation[]
Array that indicates how much to deposit or withdraw from each market.
Manually accrues fees and mints shares to the fee recipient.
Iterates through the supply queue to deposit the desired amount of assets. Reverts if the deposit amount cannot be filled due to the allocation cap or the supply cap.
External functions calling this must be non-reentrant in case the underlying IonPool implements callback logic.
Parameters
assets
uint256
The amount of assets that will attempt to be supplied.
Iterates through the withdraw queue to withdraw the desired amount of assets. Will revert if there is not enough liquidity or if trying to withdraw more than the caller owns.
External functions calling this must be non-reentrant in case the underlying IonPool implements callback logic.
Parameters
assets
uint256
The desired amount of assets to be withdrawn.
Transfers the specified amount of assets from the sender, supplies into the underlying IonPool markets, and mints a corresponding amount of shares.
All incoming deposits are deposited in the order specified in the deposit queue.
Parameters
assets
uint256
Amount of tokens to be deposited.
receiver
address
The address to receive the minted shares.
Mints the specified amount of shares and deposits a corresponding amount of assets.
Converts the shares to assets and iterates through the deposit queue to allocate the deposit across the supported markets.
Parameters
shares
uint256
The exact amount of shares to be minted.
receiver
address
The address to receive the minted shares.
Withdraws specified amount of assets from IonPools and sends them to the receiver in exchange for burning the owner's vault shares.
All withdraws are withdrawn in the order specified in the withdraw queue. The owner needs to approve the caller to spend their shares.
Parameters
assets
uint256
The exact amount of assets to be transferred out.
receiver
address
The receiver of the assets transferred.
owner
address
The owner of the vault shares.
Redeems the exact amount of shares and receives a corresponding amount of assets.
After withdrawing assets
, the user gets exact assets
out. But in the IonPool, the resulting total underlying claim may have decreased by a bit above the assets
amount due to rounding in the pool's favor. In that case, the resulting totalAssets()
will be smaller than just the newTotalAssets - assets
. Predicting the exact resulting totalAssets() requires knowing how much liquidity is being withdrawn from each pool, which is not possible to know until the actual iteration on the withdraw queue. So we acknowledge the dust difference here. If the lastTotalAssets
is slightly greater than the actual totalAssets
, the impact will be that the calculated interest accrued during fee distribution will be slightly less than the true value.
Parameters
shares
uint256
The exact amount of shares to be burned and redeemed.
receiver
address
The address that receives the transferred assets.
owner
address
The address that holds the shares to be redeemed.
Returns the decimals places of the token.
Returns the maximum amount of assets that the vault can supply on Ion.
The max deposit amount is limited by the vault's allocation cap and the underlying IonPools' supply caps.
Returns
<none>
uint256
The max amount of assets that can be supplied.
Returns the maximum amount of vault shares that can be minted.
Max mint is limited by the max deposit based on the Vault's allocation caps and the IonPools' supply caps. The conversion from max suppliable assets to shares preempts the shares minted from fee accrual.
Returns
<none>
uint256
The max amount of shares that can be minted.
Returns the maximum amount of assets that can be withdrawn.
Max withdraw is limited by the owner's shares and the liquidity available to be withdrawn from the underlying IonPools. The max withdrawable claim is inclusive of accrued interest and the extra shares minted to the fee recipient.
Parameters
owner
address
The address that holds the assets.
Returns
assets
uint256
The max amount of assets that can be withdrawn.
Calculates the total withdrawable amount based on the available liquidity in the underlying pools and converts it to redeemable shares.
Max redeem is derived from รงonverting the _maxWithdraw
to shares. The conversion takes into account the total supply and total assets inclusive of accrued interest and the extra shares minted to the fee recipient.
Parameters
owner
address
The address that holds the shares.
Returns
<none>
uint256
The max amount of shares that can be withdrawn.
Returns the total claim that the vault has across all supported IonPools.
IonPool.balanceOf
returns the rebasing balance of the lender receipt token that is pegged 1:1 to the underlying supplied asset.
Returns
assets
uint256
The total assets held on the contract and inside the underlying pools by this vault.
Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given current on-chain conditions.
Inclusive of manager fee.
Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given current on-chain conditions.
Inclusive of manager fee.
Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, given current on-chain conditions.
Inclusive of manager fee.
Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, given current on-chain conditions.
Inclusive of manager fee.
The total accrued vault revenue is the difference in the total iToken holdings from the last accrued timestamp and now.
NOTE The IERC4626 natspec recommends that the _convertToAssets
and _convertToShares
"MUST NOT be inclusive of any fees that are charged against assets in the Vault." However, all deposit/mint/withdraw/redeem flow will accrue fees before processing user requests, so manager fee must be accounted for to accurately reflect the resulting state. All preview functions will rely on this WithFees
version of the _convertTo
function.
NOTE The IERC4626 natspec recommends that the _convertToAssets
and _convertToShares
"MUST NOT be inclusive of any fees that are charged against assets in the Vault." However, all deposit/mint/withdraw/redeem flow will accrue fees before processing user requests, so manager fee must be accounted for to accurately reflect the resulting state. All preview functions will rely on this WithFees
version of the _convertTo
function.
Returns the amount of shares that the vault would exchange for the amount of assets
provided. This function is used to calculate the conversion between shares and assets with parameterizable total supply and total assets variables.
Returns the amount of assets that the vault would exchange for the amount of shares
provided. This function is used to calculate the conversion between shares and assets with parameterizable total supply and total assets variables.
Emulates the actual _withdrawFromIonPool
accounting to predict accurately how much of the input assets will be left after withdrawing as much as it can. The difference between this return value and the input assets
is the exact amount that will be withdrawn.
Returns
<none>
uint256
The remaining assets to be withdrawn. NOT the amount of assets that were withdrawn.
The max amount of assets withdrawable from a given IonPool considering the vault's claim and the available liquidity. A minimum of this contract's total claim on the underlying and the available liquidity in the pool.
Returns
<none>
uint256
The max amount of assets withdrawable from this IonPool.
The max amount of assets depositable to a given IonPool. Depositing the minimum between the two diffs ensures that the deposit will not violate the allocation cap or the supply cap.
Returns
<none>
uint256
The max amount of assets depositable to this IonPool.
Returns the array representation of the supportedMarkets
set.
Returns
<none>
address[]
Array of supported IonPools.
Returns whether the market is part of the supportedMarkets
set.
Parameters
pool
address
The address of the IonPool to be checked.
Returns
<none>
bool
The pool is supported if true. If not, false.
Returns the element in the array representation of supportedMarkets
. index
must be strictly less than the length of the array.
Parameters
index
uint256
The index to be queried on the supportedMarkets
array.
Returns
<none>
address
Address at the index of supportedMarkets
.
Returns the index of the specified market in the array representation of supportedMarkets
.
The _positions
mapping inside the EnumerableSet.Set
returns the index of the element in the _values
array plus 1. The _positions
value of 0 means that the value is not in the set. If the value is not in the set, this call will revert. Otherwise, it will return the position - 1
value to return the index of the element in the array.
Parameters
pool
address
The address of the IonPool to be queried.
Returns
<none>
uint256
The index of the pool's location in the array. The return value will always be greater than zero as this function would revert if the market is not part of the set.
Length of the array representation of supportedMarkets
.
Returns
<none>
uint256
The length of the supportedMarkets
array.