Missing checks and some access controls on critical functions
Description
The knock-in (KI) feature provides downside protection for investors' deposited capital. Specifically, investors will receive 100% of their initial investment in the FCN even if crypto asset prices are falling. In this case, unless crypto asset prices fall by 50% or more versus the day the vault started, investors' capital will be protected (unlike vanilla option strategies). If however the FCN does KI, the principal returned at expiry is equal to the lesser of 100% or the fallen asset price percentage of its initial price.
To determine if a knock-in event has occurred, Cega uses option barriers.
It is safe to assume that investors will choose their investments by carefully considering a few factors. One of these factors may be to check what the knock-in barrier level is set to in relation to the price volatility of the option asset tokens. For example, if the token price is highly volatile, and the knock-in barrier level is at 90%, then there is a high chance that a knock-in event will occur, which may cause the investor to decide against investing in that specific vault.
Currently, there exists three functions that the trader admin can use to add, update, and remove knock-in barriers. These are the addOptionBarrier()
, updateOptionBarrier()
, and removeOptionBarrier()
functions, respectively. An important characteristic of these functions is that they do not require the vault to be in any specific state, meaning the trader admin can add or update option barriers at any time, even after the investor's deposits are locked in.
Furthermore, the parameters of a knock-in barrier can be arbitrary, as there are no sanity checks to ensure they are within certain limits.
function addOptionBarrier(address vaultAddress, OptionBarrier calldata optionBarrier) public onlyTraderAdmin {
FCNVaultMetadata storage metadata = vaults[vaultAddress];
metadata.optionBarriers.push(optionBarrier);
metadata.optionBarriersCount++;
}
This will reduce the investor's trust in the protocol because although they might note a very low knock-in barrier level initially (i.e., a low chance of a knock-in event occurring), they will know that the level may be raised at any moment, which makes the investment inherently risky.
There also exists a setKnockInStatus()
function that the trader admin can use to arbitrarily set a vault's knock-in status to true
.
Finally, the trader admin can also use the oracle's updateRoundData()
function to arbitrarily control the option asset token price returned by the oracle. This could also be used to trigger a knock-in event.
Impact
Investors' trust in the protocol is significantly reduced due to missing checks and incorrect access controls in critical state-modifying functions.
Recommendations
For the option barrier functionality, consider requiring a vault state of VaultStatus.NotTraded
to modify any option barriers in the vault.
For the setKnockInStatus()
function, consider removing it completely. Alternatively, place it behind the onlyDefaultAdmin
modifier instead.
For the updateRoundData()
function, consider changing its access control such that only the default admin multi-sig or the operator admin role can call it.
Remediation
The client has acknowledged and fixed all of the above issues according to our recommendations. This was fixed in commit 834fe7ed↗.