Assessment reports>Anzen Finance>Low findings>Protection logic in ,rescueERC20, can be bypassed
Category: Business Logic

Protection logic in rescueERC20 can be bypassed

Low Severity
Low Impact
Low Likelihood

Description

The sUSDz contract provides the staking feature for USDz holders. Specifically, a user can stake their USDz tokens into the sUSDz contract in order to receive the yield that is deposited by the yield manager. The yield manager deposits the full amount of yield when they start the new vesting period.

The sUSDz contract has the rescueERC20 function, which allows the pool manager to withdraw tokens that may be mistakenly transferred to this contract. To prevent users assets from being withdrawn, there is logic that ensures the deposited asset is not withdrawn through this function:

function rescueERC20(IERC20 token, address to, uint256 amount) external onlyRole(POOL_MANAGER_ROLE) {
    // If is USDz, check pooled amount first.
    if (address(token) == asset()) {
        require(amount <= token.balanceOf(address(this)).sub(totalAssets()), "USDZ_RESCUE_AMOUNT_EXCEED_DEBIT");
    }
    token.safeTransfer(to, amount);
}

However, it should be noted that the return value of the totalAssets function does not include the unvested amount:

function totalAssets() public view override returns (uint256) {
    uint256 unvested = getUnvestedAmount();
    return pooledUSDz.sub(unvested);
}

Impact

The pool manager can withdraw the part of yield that is not vested to users through the rescueERC20 function, despite of the protective logic referenced earlier.

Recommendations

Consider modifying the protection logic of the rescueERC20 function to ensure that USDz tokens of the amount pooledUSDz is left in the contract.

Remediation

This issue has been acknowledged by Anzen Group Ltd., and a fix was implemented in commit e64b88de.

Zellic © 2024Back to top ↑