Omniscia Mitosis Audit
BasicVault Manual Review Findings
BasicVault Manual Review Findings
BVT-01M: Bypass of Halt Restrictions
Type | Severity | Location |
---|---|---|
Logical Fault | BasicVault.sol:L168-L178, L180-L190 |
Description:
The BasicVault::manualDeposit
and BasicVault::manualRedeem
functions will bypass the BasicVault::withNoHalt
security modifier.
Impact:
The severity of this exhibit will be adjusted based on the actions of the Mitosis team.
Example:
168function manualDeposit(uint256 amount, address receiver) external returns (uint256) {169 if (!_isAllowed(_msgSender(), Action.Mint)) {170 revert Error.Unauthorized();171 }172
173 uint256 added = _getUtilStorageV1()._cap.addLoad(amount, receiver);174
175 _deposit(added, receiver);176
177 return added;178}179
180function manualRedeem(uint256 amount, address receiver) external returns (uint256) {181 if (!_isAllowed(_msgSender(), Action.Burn)) {182 revert Error.Unauthorized();183 }184
185 uint256 subbed = _getUtilStorageV1()._cap.subLoad(amount, receiver);186
187 _redeem(subbed, receiver);188
189 return subbed;190}
Recommendation:
We advise the Mitosis team to evaluate whether this is intended as the BasicVault::withNoHalt
function failing indicates a critical failure in the contract that should deny cross-chain messages.
Alleviation (d94d2a63d25db5623d69dc33aea6e4fdd011d669):
The BasicVault::withNoHalt
modifier has been properly introduced to the referenced functions, alleviating this exhibit.
BVT-02M: Improper Deposit Log Maintenance
Type | Severity | Location |
---|---|---|
Logical Fault | BasicVault.sol:L242 |
Description:
The first DepositLog
introduced to the logs
of the receiver will have a cumulative
value of 0
whilst it should be initialized to the amount
deposited.
Impact:
This recommendation is simply semantic as the cumulative value inclusive of the latest deposit can be calculated by summing cumulative
with amount
. As such, we will assign a severity depending on the intended approach by the Mitosis team.
Example:
242DepositLog memory log = DepositLog({cumulative: 0, amount: amount, at: block.timestamp});243
244if (info.logs.length > 0) {245 log.cumulative = info.logs[info.logs.length - 1].cumulative + amount;246}
Recommendation:
We advise the cumulative
value to be set to amount
as well, ensuring that it properly represents the cumulative deposits up to and including the latest deposit.
Alleviation (5297bb74fa5cb1c63239172a7a7a3a7c8ce808e3):
The Mitosis team evaluated this exhibit and opted to retain the current behaviour in place as the semantic they wish to follow is to explicitly sum the cumulative
and amount
values of a log.
As such, we consider this exhibit nullified as it described desirable behaviour.
BVT-03M: Inexistent Initialization Protection of Base Implementation
Type | Severity | Location |
---|---|---|
Language Specific | BasicVault.sol:L84 |
Description:
The contract is meant to be upgradeable yet does not properly protect its logic deployment from malicious initializations.
Example:
71contract BasicVault is72 IVault,73 ERC20PermitUpgradeable,74 OwnableUpgradeable,75 BasicVaultStorageV1,76 BasicVaultUtilStorageV177{78 event Deposit(address indexed account, address indexed token, uint256 amount);79 event Redeem(address indexed account, address indexed token, uint256 amount);80
81 event Halted(Action action);82 event Resumed(Action action);83
84 function initialize(address owner, IERC20 asset, string memory name, string memory symbol) public initializer {85 __ERC20_init(name, symbol);86 __ERC20Permit_init(name);87 __Ownable_init();88 _transferOwnership(owner);89
90 StorageV1 storage $ = _getStorageV1();91 $._underlyingDecimals = IERC20Metadata(address(asset)).decimals();92 $._asset = asset;93 }
Recommendation:
We advise a constructor
to be introduced that either invokes the initializer
modifier of the Initializable
contract or invokes the Initializable::_disableInitializers
function to prevent the base implementation from ever being initialized.
Alleviation (58e8cc66dfa900c03c47df78f5170d9960005629):
A BasicVault::constructor
has been introduced invoking the Initializable::initialize
modifier thereby preventing re-initializations as long as the contract does not utilize a versioned initialization system.
If such a system is expected, we advise the Initializable::_disableInitializers
function instead.
BVT-04M: Inexistent Consumption of Allowance
Type | Severity | Location |
---|---|---|
Logical Fault | BasicVault.sol:L228-L232 |
Description:
As evidenced in EETHDepositHelper::_redeem
, the BasicVault::_redeem
function should consume allowance from the caller to burn their tokens but it does not.
Impact:
Redemption operations on the BasicVault
do not require an allowance which goes against common practice.
Example:
228function _redeem(uint256 amount, address receiver) internal {229 _pruneDepositLog(amount, receiver);230 _burn(_msgSender(), amount);231 emit Redeem(receiver, address(_getStorageV1()._asset), amount);232}
Recommendation:
We advise allowance to be incorporated, ensuring that the caller has correctly authorized the redemption operation to the BasicVault
.
Alleviation (d94d2a63d2):
The Mitosis team evaluated this exhibit and opted to retain the current behaviour in place as they deem explicit approvals a waste of gas.
We would like to note that in such a case, the approval operation of the EETHDepositHelper::_redeem
function needs to be removed rendering this exhibit partially alleviated.
Alleviation (58e8cc66df):
The approval increase in EETHDepositHelper::_redeem
has been removed as advised, fully alleviating this exhibit.
BVT-05M: Improper Assumption of Binary Search
Type | Severity | Location |
---|---|---|
Logical Fault | BasicVault.sol:L268-L277 |
Description:
The BasicVault::_pruneDepositLog
function assumes that the binary search it implements will always detect a deposit log whose redemption period has elapsed; this is not always the case as the binary search will terminate with a valid index but potentially invalid log.
Impact:
The redemption period is presently not enforced, effectively representing as an absent feature of the system.
Example:
251function _pruneDepositLog(uint256 amount, address receiver) internal {252 UtilStorageV1 storage $ = _getUtilStorageV1();253
254 if ($._redeemPeriod <= 0) {255 return;256 }257
258 DepositInfo storage info = $._deposits[receiver];259
260 if (info.logs.length == 0) {261 info.resolved -= amount;262 return;263 }264
265 uint256 high = info.logs.length;266 uint256 low = info.lastLogIdx;267
268 while (low < high) {269 uint256 mid = Math.average(low, high);270 if (info.logs[mid].at + $._redeemPeriod > block.timestamp) {271 high = mid;272 } else {273 low = mid + 1;274 }275 }276
277 uint256 extracted = info.logs[high - 1].cumulative - info.logs[info.lastLogIdx].cumulative;278
279 info.lastLogIdx = high - 1;280 info.resolved = (info.resolved + extracted) - amount;281
282 return;283}
Recommendation:
We advise the code to introduce one more conditional that ensures the info.logs
entry that the binary search yielded has had its redemption period elapsed, ensuring that only redeemable logs can be consumed by redemption operations on the BasicVault
.
Alleviation (58e8cc66df):
The code has been refactored across multiple functions to properly support the redeemPeriod
mechanism of the contract, yielding a bool
that indicates a claimable entry has been found in the BasicVault::_searchClaimableDepositIndex
function while conditionally pruning and ensuring the redemption amount has been met in the BasicVault::_redeem
function.
As a result of these changes, we consider the redemption period limitation properly upheld by the contract in all circumstances apart from transfers. Specifically, a user can circumvent the redemption period limitation by transferring their EIP-20 balance to a secondary account and redeeming from it.
We advise the code to permit transfers of up to the redeemable amount instead, properly maintaining the deposit logs as if a "withdrawal" occurred for the redeemed assets. Identically, the balance of a user should be split between assets-to-be-unlocked via the redemption period and already-unlocked balance that they can freely transfer.
Alleviation (67e2cd4ae4):
The deposit log and redemption period concepts have been eliminated from the codebase entirely, rendering this exhibit no longer applicable.
BVT-06M: Improper Protection Against EIP-777 Re-Entrancies
Type | Severity | Location |
---|---|---|
Logical Fault | BasicVault.sol:L138, L147 |
Description:
The BasicVault::deposit
function, despite what the in-line documentation states, will result in a corrupted system state during an EIP-777 re-entrancy. Specifically, the Cap::addLoad
function will be invoked before the transfer is performed which will update the _load
of the particular epoch as well as relay messages if need be to other chains.
This can cause redemptions of higher amounts than permitted to occur before the actual deposit goes through which is ill-advised.
Impact:
The system is presently insecure against EIP-777 re-entrancies as it will contain a corrupt system state during any re-entrancy be it local or cross-contract.
Example:
135function deposit(uint256 amount, address receiver) external withNoHalt(Action.Deposit) {136 StorageV1 storage $ = _getStorageV1();137
138 uint256 added = _getUtilStorageV1()._cap.addLoad(amount, receiver);139
140 // If _asset is ERC777, `transferFrom` can trigger a reentrancy BEFORE the transfer happens through the141 // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,142 // calls the vault, which is assumed not malicious.143 //144 // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the145 // assets are transferred and before the shares are minted, which is a valid state.146 // slither-disable-next-line reentrancy-no-eth147 SafeERC20.safeTransferFrom($._asset, _msgSender(), address(this), added);148
149 _deposit(added, receiver);150}
Recommendation:
We recommend that the statements are re-ordered, performing the inbound token transfer at the very beginning of the function and thus ensuring that the system contains a valid state at all times.
Alleviation (5297bb74fa5cb1c63239172a7a7a3a7c8ce808e3):
The transfer of the EIP-20 / EIP-777 asset has been re-ordered to be performed before the Cap::addLoad
function invocation, alleviating this exhibit.