This repository has been archived by the owner on Nov 19, 2023. It is now read-only.
xiaoming90 - VaultAccountSecondaryDebtShareStorage.maturity
will be cleared prematurely
#183
Labels
High
A valid High severity issue
Reward
A payout will be made for this issue
Sponsor Confirmed
The sponsor acknowledged this issue is valid
Will Fix
The sponsor confirmed this issue will be fixed
xiaoming90
high
VaultAccountSecondaryDebtShareStorage.maturity
will be cleared prematurelySummary
VaultAccountSecondaryDebtShareStorage.maturity
will be cleared prematurely during liquidationVulnerability Detail
If both the
accountDebtOne
andaccountDebtTwo
of secondary currencies are zero, Notional will consider both debt shares to be cleared to zero, and the maturity will be cleared as well as shown below.https://github.com/sherlock-audit/2023-03-notional/blob/main/contracts-v2/contracts/internal/vaults/VaultSecondaryBorrow.sol#L495
VaultLiquidationAction.deleverageAccount
functionWithin the
VaultLiquidationAction.deleverageAccount
function, it will call the_reduceAccountDebt
function.Referring to the
_reduceAccountDebt
function below. Assume that thecurrencyIndex
reference to a secondary currency. In this case, the else logic in Line 251 will be executed. An important point to take note of that is critical to understand this bug is that only ONE of the prime rates will be set as it assumes that the other prime rate will not be used (Refer to Line 252 - 255). However, this assumption is incorrect.Assume that the
currencyIndex
is1
. ThennetUnderlyingDebtOne
parameter will be set to a non-zero value (depositUnderlyingInternal
) at Line 261 whilenetUnderlyingDebtTwo
parameter will be set to zero at Line 262. This is because, in Line 263 of the_reduceAccountDebt
function, thepr[0]
will be set to the prime rate, while thepr[1]
will be zero or empty. It will then proceed to call theVaultSecondaryBorrow.updateAccountSecondaryDebt
https://github.com/sherlock-audit/2023-03-notional/blob/main/contracts-v2/contracts/external/actions/VaultLiquidationAction.sol#L239
Within the
updateAccountSecondaryDebt
function, at Line 272, assume thataccountStorage.accountDebtTwo
is100
. However, sincepr[1]
is not initialized, theVaultStateLib.readDebtStorageToUnderlying
will return a zero value and set theaccountDebtTwo
to zero.Assume that the liquidator calls the
deleverageAccount
function to clear all the debt of thecurrencyIndex
secondary currency. Line 274 will be executed, andaccountDebtOne
will be set to zero.Note that at this point, both
accountDebtOne
andaccountDebtTwo
are zero. At Line 301, the_setAccountMaturity
will set theaccountStorage.maturity = 0
, which clears the vault account's maturity.An important point here is that the liquidator did not clear the
accountDebtTwo
. Yet,accountDebtTwo
became zero in memory during the execution and caused Notional to wrongly assume that both debt shares had been cleared to zero.https://github.com/sherlock-audit/2023-03-notional/blob/main/contracts-v2/contracts/internal/vaults/VaultSecondaryBorrow.sol#L256
The final state will be
VaultAccountSecondaryDebtShareStorage
as follows:maturity
andaccountDebtOne
are zeroaccountDebtTwo
= 100https://github.com/sherlock-audit/2023-03-notional/blob/main/contracts-v2/contracts/global/Types.sol#L551
Firstly, it does not make sense to have
accountDebtTwo
but no maturity in storage, which also means the vault account data is corrupted. Secondly, whenmaturity
is zero, it also means that the vault account did not borrow anything from Notional. Lastly, many vault logic would break since it relies on the maturity value.VaultLiquidationAction.liquidateVaultCashBalance
functionThe root cause lies in the implementation of the
_reduceAccountDebt
function. SinceliquidateVaultCashBalance
function calls the_reduceAccountDebt
function to reduce the debt of the vault account being liquidated, the same issue will occur here.Impact
Any vault logic that relies on the
VaultAccountSecondaryDebtShareStorage
's maturity value would break since it has been cleared (set to zero). For instance, a vault account cannot be settled anymore as the followingsettleSecondaryBorrow
function will always revert. SincestoredMaturity == 0
butaccountDebtTwo
is not zero, Line 399 below will always revert.As a result, a vault account with secondary currency debt cannot be settled. This also means that the vault account cannot exit since a vault account needs to be settled before exiting, causing users' assets to be stuck within the protocol.
https://github.com/sherlock-audit/2023-03-notional/blob/main/contracts-v2/contracts/internal/vaults/VaultSecondaryBorrow.sol#L385
In addition, the vault account data is corrupted as there is a secondary debt without maturity, which might affect internal accounting and tracking.
Code Snippet
https://github.com/sherlock-audit/2023-03-notional/blob/main/contracts-v2/contracts/external/actions/VaultLiquidationAction.sol#L239
Tool used
Manual Review
Recommendation
Fetch the prime rate of both secondary currencies because they are both needed within the
updateAccountSecondaryDebt
function when converting debt storage to underlying.The text was updated successfully, but these errors were encountered: