Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QA Report #165

Open
code423n4 opened this issue May 2, 2022 · 0 comments
Open

QA Report #165

code423n4 opened this issue May 2, 2022 · 0 comments
Labels
bug Something isn't working QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax

Comments

@code423n4
Copy link
Contributor

1. SuperVault uses unchecked collateral transfer and transferFrom with arbitrary ERC20 (low)

Whenever an ERC20 that do not revert on transfer failure is used and transfer / transferFrom fails and return false which will be ignored, there will be a contract malfunction, the end result of which depends on the current state of the contract.

Placing severity to be low for 3 functions that are onlyOwner as in such case the behavior can be controlled by the trusted caller.

Proof of Concept

leverage (onlyOwner):

https://github.com/code-423n4/2022-04-mimo/blob/b18670f44d595483df2c0f76d1c57a7bfbfbc083/supervaults/contracts/SuperVault.sol#L129-L129

IERC20(asset).transferFrom(msg.sender, address(this), depositAmount);

emptyVault (onlyOwner):

https://github.com/code-423n4/2022-04-mimo/blob/b18670f44d595483df2c0f76d1c57a7bfbfbc083/supervaults/contracts/SuperVault.sol#L237-L237

collateral.transfer(msg.sender, collateral.balanceOf(address(this)));

depositAndBorrowFromVault (onlyOwner):

https://github.com/code-423n4/2022-04-mimo/blob/b18670f44d595483df2c0f76d1c57a7bfbfbc083/supervaults/contracts/SuperVault.sol#L290-L290

token.transferFrom(msg.sender, address(this), depositAmount);

Some ERC20 do not revert on transfer failure:

https://github.com/d-xo/weird-erc20#no-revert-on-failure

Recommended Mitigation Steps

Require transfer success as it is done elsewhere in the contract or employ OpenZeppelin's SafeERC20

2. PARMinerV2's liquidate doesn't check the router call success (non-critical)

On router call failure there will be LM104 error issued, which might not be best for failure description.

Proof of Concept

router can be arbitrary and router.call is unchecked:

https://github.com/code-423n4/2022-04-mimo/blob/b18670f44d595483df2c0f76d1c57a7bfbfbc083/core/contracts/liquidityMining/v2/PARMinerV2.sol#L126-L128

    router.call(dexTxData);
    _par.safeTransfer(msg.sender, _liquidateCallerReward);
    require(_par.balanceOf(address(this)) > parBalanceBefore, "LM104");

Recommended Mitigation Steps

Requiring the call success is advised with a tailored error

3. Manual updateBoost is required before GenericMinerV2 become operational (non-critical)

releaseRewards calls _releaseRewards before _updateBoost:

https://github.com/code-423n4/2022-04-mimo/blob/b18670f44d595483df2c0f76d1c57a7bfbfbc083/core/contracts/liquidityMining/v2/GenericMinerV2.sol#L80-L86

  function releaseRewards(address _user) public virtual override {
    UserInfo memory _userInfo = _users[_user];
    _releaseRewards(_user, _userInfo);
    _userInfo.accAmountPerShare = _accMimoAmountPerShare;
    _userInfo.accParAmountPerShare = _accParAmountPerShare;
    _updateBoost(_user, _userInfo);
  }

As only _updateBoost can increase _totalStakeWithBoost, the _releaseRewards() will fail by calling _refresh():

https://github.com/code-423n4/2022-04-mimo/blob/b18670f44d595483df2c0f76d1c57a7bfbfbc083/core/contracts/liquidityMining/v2/GenericMinerV2.sol#L209-L212

  function _releaseRewards(address _user, UserInfo memory _userInfo) internal {
    uint256 pendingMIMO = _pendingMIMO(_userInfo.stakeWithBoost, _userInfo.accAmountPerShare);
    uint256 pendingPAR = _pendingPAR(_userInfo.stakeWithBoost, _userInfo.accParAmountPerShare);
    _refresh();

This is because _refresh() performs division by _totalStakeWithBoost without checking that it is non-zero:

https://github.com/code-423n4/2022-04-mimo/blob/b18670f44d595483df2c0f76d1c57a7bfbfbc083/core/contracts/liquidityMining/v2/GenericMinerV2.sol#L271-L273

    _accMimoAmountPerShare = _accMimoAmountPerShare.add(mimoReward.rayDiv(_totalStakeWithBoost));
    _parBalanceTracker = currentParBalance;
    _accParAmountPerShare = _accParAmountPerShare.add(parReward.rayDiv(_totalStakeWithBoost));

While it will be zero on releaseRewards or _updateStake first run as _totalStakeWithBoost wasn't updated yet.

Recommended Mitigation Steps

Consider checking that _totalStakeWithBoost is not zero before running the logic that use it as a divisor.

@code423n4 code423n4 added bug Something isn't working QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax labels May 2, 2022
code423n4 added a commit that referenced this issue May 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax
Projects
None yet
Development

No branches or pull requests

1 participant