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

Lambda Convert doesn't work because of cap exceed penalty

Summary

Cap exceed penalty was introduced in Beanstalk 3.

Convert can't be performed if penalty should be applied. Documentation states that any deposit can be converted to the same deposit (it increases deposit's BDV) - it's called Lambda convert. However according to this new exceed cap penalty Lambda converts can't be performed most of the times.

Vulnerability Details

After conversion is executed it checks that penalty is 0:
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/df2dd129a878d16d4adc75049179ac0029d9a96b/protocol/contracts/beanstalk/silo/ConvertFacet.sol#L90

function convert(
bytes calldata convertData,
int96[] memory stems,
uint256[] memory amounts
)
external
payable
fundsSafu
noSupplyChange
nonReentrant
returns (int96 toStem, uint256 fromAmount, uint256 toAmount, uint256 fromBdv, uint256 toBdv)
{
address toToken;
address fromToken;
// if the convert is a well <> bean convert, cache the state to validate convert.
LibPipelineConvert.PipelineConvertData memory pipeData = LibPipelineConvert.getConvertState(
convertData
);
@> (toToken, fromToken, toAmount, fromAmount) = LibConvert.convert(convertData);
...
// check for potential penalty
@> LibPipelineConvert.checkForValidConvertAndUpdateConvertCapacity(
pipeData,
convertData,
fromToken,
toToken,
fromBdv
);
...
}
function checkForValidConvertAndUpdateConvertCapacity(
PipelineConvertData memory pipeData,
bytes calldata convertData,
address fromToken,
address toToken,
uint256 fromBdv
) public {
...
require(
@> pipeData.stalkPenaltyBdv == 0,
"Convert: Penalty would be applied to this convert, use pipeline convert"
);
}
}

When we dive into that penalty logic, we stop here. As you can see it cpplies penalty if overallConvertCapacityUsed exceeds overallCappedDeltaB:
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/df2dd129a878d16d4adc75049179ac0029d9a96b/protocol/contracts/libraries/Convert/LibConvert.sol#L284

function calculateConvertCapacityPenalty(
uint256 overallCappedDeltaB,
uint256 overallAmountInDirectionOfPeg,
address inputToken,
uint256 inputTokenAmountInDirectionOfPeg,
address outputToken,
uint256 outputTokenAmountInDirectionOfPeg
) internal view returns (uint256 cumulativePenalty, PenaltyData memory pdCapacity) {
AppStorage storage s = LibAppStorage.diamondStorage();
ConvertCapacity storage convertCap = s.sys.convertCapacity[block.number];
// first check overall convert capacity, if none remaining then full penalty for amount in direction of peg
if (convertCap.overallConvertCapacityUsed >= overallCappedDeltaB) {
cumulativePenalty = overallAmountInDirectionOfPeg;
} else if (
overallAmountInDirectionOfPeg >
overallCappedDeltaB.sub(convertCap.overallConvertCapacityUsed)
) {
cumulativePenalty =
overallAmountInDirectionOfPeg -
overallCappedDeltaB.sub(convertCap.overallConvertCapacityUsed);
}
...
}

Impact

Lambda Converts cannot be performed due to cap exceed penalty. It breaks invariant stated in docs:

*Any token on the Deposit Whitelist can be Converted to the same token in order to allow Stalkholders to update the BDV of their LP tokens when their BDV increases due to impermanent loss.

Tools Used

Manual Review

Recommendations

Refactor Convert logic to exclude cap exceed penalty from Lambda Convert.

Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Appeal created

T1MOH Submitter
11 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Lambda Convert doesn't work because of cap exceed penalty

giovannidisiena Auditor
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

Lambda Convert doesn't work because of cap exceed penalty

Support

FAQs

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