DeFiHardhat
21,000 USDC
View results
Submission Details
Severity: medium
Invalid

Change of UnripeToken via `addUnripeToken()` will cause incorrect calculation

Summary

When addUnripeToken() is called by the admin, it ignores to account for any existing token balance in the current s.u[unripeToken].underlyingToken before updating the underlyingToken to a new underlyingToken. Such existing balance is migrated from the old to the new underlyingToken. This will result in a incorrect calculation in getPenalizedUnderlying function when it is calculated chop.

Vulnerability Details

The addUnripeToken function in the UnripeFacet contract allows the addition of an unripe token with its corresponding underlying token and Merkle root. However, if there is already an existing underlying token associated with the unripe token, this function will override the existing underlying token without any checks. This can result in the new unripe token incorrectly assuming the non-zero balance of the previous underlying token. This can lead to a loss of asset tracking.

function addUnripeToken(
address unripeToken,
address underlyingToken,
bytes32 root
) external payable nonReentrant {
LibDiamond.enforceIsOwnerOrContract();
s.u[unripeToken].underlyingToken = underlyingToken;
s.u[unripeToken].merkleRoot = root;
emit AddUnripeToken(unripeToken, underlyingToken, root);
}

So the addUnripeToken function does not check if the provided unripeToken is already present in the s.u mapping. If the underlyingToken is changed, the balance of the previous underlying token is affected. This leads to incorrect calculations when redeeming assets, as the balance associated with the unripe token will not accurately reflect its true value.

function getPenalizedUnderlying(
address unripeToken,
uint256 amount,
uint256 supply
) internal view returns (uint256 redeem) {
//.....
// redeem = currentRipeUnderlying * (usdValueRaised/totalUsdNeeded) * UnripeAmountIn/UnripeSupply
@>> uint256 underlyingAmount = s.u[unripeToken].balanceOfUnderlying;
redeem = underlyingAmount.mul(s.recapitalized).div(totalUsdNeeded).mul(amount).div(supply);
// cap `redeem to `balanceOfUnderlying in the case that `s.recapitalized` exceeds `totalUsdNeeded`.
// this can occur due to unripe LP chops.
if(redeem > underlyingAmount) redeem = underlyingAmount;
}

Impact

The function getPenalizedUnderlying calculates the redeem amount of underlying tokens based on the balance of the underlying token associated with the unripe token. If the underlying token is incorrectly overridden, the redeem calculation will be incorrect.

Tools Used

Manual Review

Recommendations

function addUnripeToken(
address unripeToken,
address underlyingToken,
bytes32 root
) external payable nonReentrant {
LibDiamond.enforceIsOwnerOrContract();
+ require(s.u[unripeToken].underlyingToken == address(0), "Unripe: Token already exists");
+ require(s.u[unripeToken].balanceOfUnderlying == 0, "Unripe: Underlying balance > 0");
s.u[unripeToken].underlyingToken = underlyingToken;
s.u[unripeToken].merkleRoot = root;
emit AddUnripeToken(unripeToken, underlyingToken, root);
}
Updates

Lead Judging Commences

giovannidisiena Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.