DeFiHardhat
35,000 USDC
View results
Submission Details
Severity: low
Invalid

Possible Reentrancy attack on `addUnderlying` function

Summary

The addUnderlying function within the LibFertilizer library is responsible for adding underlying assets to the fertilizer system. It calculates the number of newly deposited beans to be minted based on the amount of tokens contributed and the current recapitalization status. Then, it calculates the number of beans to be added as liquidity provider (LP) tokens and mints them accordingly. Afterward, it transfers the necessary tokens to the Barn Raise Well and approves the transfer of beans to the well. Finally, it adds liquidity to the well, increments the underlying balances of Unripe Tokens, and updates the recapitalization status accordingly.

Vulnerability Details

There is a potential reentrancy vulnerability in the addUnderlying function. This vulnerability arises due to the transfer of tokens and subsequent approvals within the function. An attacker could exploit this by calling the addUnderlying function recursively before the first call completes, potentially causing unexpected behavior or loss of funds.

See the following code:

function addUnderlying(uint256 tokenAmountIn, uint256 usdAmount, uint256 minAmountOut) internal {
AppStorage storage s = LibAppStorage.diamondStorage();
// Calculate how many new Deposited Beans will be minted
uint256 percentToFill = usdAmount.mul(C.precision()).div(
remainingRecapitalization()
);
uint256 newDepositedBeans;
if (C.unripeBean().totalSupply() > s.u[C.UNRIPE_BEAN].balanceOfUnderlying) {
newDepositedBeans = (C.unripeBean().totalSupply()).sub(
s.u[C.UNRIPE_BEAN].balanceOfUnderlying
);
newDepositedBeans = newDepositedBeans.mul(percentToFill).div(
C.precision()
);
}
// Calculate how many Beans to add as LP
uint256 newDepositedLPBeans = usdAmount.mul(C.exploitAddLPRatio()).div(
DECIMALS
);
// Mint the Deposited Beans to Beanstalk.
C.bean().mint(
address(this),
newDepositedBeans
);
// Mint the LP Beans and add liquidity to the well.
address barnRaiseWell = LibBarnRaise.getBarnRaiseWell();
address barnRaiseToken = LibBarnRaise.getBarnRaiseToken();
C.bean().mint(
address(this),
newDepositedLPBeans
);
IERC20(barnRaiseToken).transferFrom(
msg.sender,
address(this),
uint256(tokenAmountIn)
);
IERC20(barnRaiseToken).approve(barnRaiseWell, uint256(tokenAmountIn));
C.bean().approve(barnRaiseWell, newDepositedLPBeans);
uint256[] memory tokenAmountsIn = new uint256[](2);
IERC20[] memory tokens = IWell(barnRaiseWell).tokens();
(tokenAmountsIn[0], tokenAmountsIn[1]) = tokens[0] == C.bean() ?
(newDepositedLPBeans, tokenAmountIn) :
(tokenAmountIn, newDepositedLPBeans);
uint256 newLP = IWell(barnRaiseWell).addLiquidity(
tokenAmountsIn,
minAmountOut,
address(this),
type(uint256).max
);
// Increment underlying balances of Unripe Tokens
LibUnripe.incrementUnderlying(C.UNRIPE_BEAN, newDepositedBeans);
LibUnripe.incrementUnderlying(C.UNRIPE_LP, newLP);
s.recapitalized = s.recapitalized.add(usdAmount);
}

Impact

The impact of such a reentrancy attack could be significant. If an attacker manages to repeatedly call the addUnderlying function before the previous calls complete, they could drain the contract of its tokens or cause it to behave unpredictably, disrupting its intended functionality and potentially causing financial losses for users.

Tools Used

Manual Review

Recommendations

One possible solution to mitigate this reentrancy vulnerability is to implement the checks-effects-interactions pattern. This pattern involves performing all necessary checks and calculations before interacting with external contracts. Specifically, in the addUnderlying function, all calculations and state updates should be completed before any external calls or token transfers are made. Additionally, reentrancy guards can be employed using mutex-like mechanisms to prevent multiple calls to critical functions from overlapping.

Updates

Lead Judging Commences

giovannidisiena Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

Informational/Invalid

Support

FAQs

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