Vault Status Checks
Some vaults may have constraints that should be enforced globally. For example, supply and/or borrow caps that restrict the maximum amount of assets that can be supplied or borrowed, as a risk minimisation.
It does not necessarily make sense to enforce these checks when checking account status. First of all, if many accounts are affected within a batch, checking these global constraints each time would be redundant.
Secondly, some types of checks require an initial snapshot of the vault state before any operations have been performed. In the case of a borrow cap, it could be that the borrow cap has been exceeded for some reason (perhaps due to a price movement, or the borrow cap itself was reduced). The vault would still want to permit repaying debts, even if the repay was insufficient to bring the total borrows below the borrow cap.
If vaults have constraints that need to be enforced globally, they may expose an external checkVaultStatus
function. In that function, the vault should evaluate application-specific logic to determine whether or not the vault is in an acceptable state. If so, it should return a special magic success value (the function selector for the checkVaultStatus
method), otherwise throw an exception.
Execution Flow
Although the vaults themselves implement checkVaultStatus
, there is no need for them to invoke this function directly. It will be called by the EVC when necessary. Instead, after performing any operation that could affect the vault's status, a vault should invoke requireVaultStatusCheck
on the EVC to schedule a future callback.
Upon receiving a requireVaultStatusCheck
call, the EVC will determine whether the current execution context defers the checks and if so, it will defer checking the status for this vault until the end of the execution context. Otherwise, the vault status check will be performed immediately.
In order to evaluate the vault status, checkVaultStatus
may need access to a snapshot of the initial vault state. If so, the recommended pattern as implemented in the reference vaults is as follows:
- Before performing any actions, each operation that requires a vault status check should first make an appropriate snapshot and store the data in transient storage (if a snapshot has not already been made)
- The operations should be performed
- The vault should then call
requireVaultStatusCheck
- When the
checkVaultStatus
callback is invoked, it should evaluate the vault status by unpacking the snapshot data stored in transient storage and compare it against the current state of the vault, and return a special magic success value, or revert if there is a violation.
As with the account status check, there is a subtle complication that vault implementations should consider if they use re-entrancy guards (which is recommended). When a vault is invoked without vault status checks being deferred (ie, directly, not via the EVC), if it calls requireVaultStatusCheck
on the EVC, the EVC will immediately call back into the vault's checkVaultStatus
function. A normal re-entrancy guard would fail upon re-entering at this point. To avoid this, vaults may wish to use the call
EVC function.