DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: low
Invalid

`LibConvert._withdrawTokens()` can emit event with incorrect values

Vulnerability Details

This function loops through stems until it withdraws amount maxTokens. As you can see it skips germinating stems. Problem is that it doesn't reset amount of germination stem.
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/df2dd129a878d16d4adc75049179ac0029d9a96b/protocol/contracts/libraries/Convert/LibConvert.sol#L466-L469

function _withdrawTokens(
address token,
int96[] memory stems,
uint256[] memory amounts,
uint256 maxTokens
) internal returns (uint256, uint256) {
...
{
a.bdvsRemoved = new uint256[](stems.length);
a.stalksRemoved = new uint256[](stems.length);
a.depositIds = new uint256[](stems.length);
// get germinating stem and stemTip for the token
LibGerminate.GermStem memory germStem = LibGerminate.getGerminatingStem(token);
while ((i < stems.length) && (a.active.tokens < maxTokens)) {
...
@> if (germStem.germinatingStem <= stems[i]) {
i++;
continue;
}
...
}
@> for (i; i < stems.length; ++i) amounts[i] = 0;
@> emit RemoveDeposits(user, token, stems, amounts, a.active.tokens, a.bdvsRemoved);
@> emit LibSilo.TransferBatch(user, user, address(0), a.depositIds, amounts);
}
...
}

Suppose a scenario:

  • User submits stems = [germinatingStem, germinatingStem, oldStem].

  • First 2 values will be skipped in cycle, and last works correctly.

  • for cycle won't clear amounts of those germinating stems because they were looped.

  • As a result LibSilo.TransferBatch will be emitted with arbitrary amount and 0 tokenId.

Impact

Events RemoveDeposits and TransferBatch will be emitted with incorrect values.

Tools Used

Manual Review

Recommendations

Reset amount before skipping germination stem, and set depositId in advance:

function _withdrawTokens(
address token,
int96[] memory stems,
uint256[] memory amounts,
uint256 maxTokens
) internal returns (uint256, uint256) {
...
// a bracket is included here to avoid the "stack too deep" error.
{
a.bdvsRemoved = new uint256[](stems.length);
a.stalksRemoved = new uint256[](stems.length);
a.depositIds = new uint256[](stems.length);
// get germinating stem and stemTip for the token
LibGerminate.GermStem memory germStem = LibGerminate.getGerminatingStem(token);
while ((i < stems.length) && (a.active.tokens < maxTokens)) {
+ a.depositIds[i] = uint256(LibBytes.packAddressAndStem(token, stems[i]));
...
if (germStem.germinatingStem <= stems[i]) {
i++;
+ amounts[i] = 0;
continue;
}
...
- a.depositIds[i] = uint256(LibBytes.packAddressAndStem(token, stems[i]));
i++;
}
for (i; i < stems.length; ++i) amounts[i] = 0;
emit RemoveDeposits(user, token, stems, amounts, a.active.tokens, a.bdvsRemoved);
emit LibSilo.TransferBatch(user, user, address(0), a.depositIds, amounts);
}
...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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