DeFiHardhatOracleProxyUpdates
100,000 USDC
View results
Submission Details
Severity: low
Invalid

```ConvertFacet::convert``` doesn't support the deposit conversions of the new whitelisted tokens

Summary

The ConvertFacet::convert allows the conversion of user deposits between different types of tokens within the ecosystem. This functionality is crucial for users looking to optimize their holdings based on market conditions and personal strategies. As indicated in the documentation (ref. docs https://docs.bean.money/almanac/peg-maintenance/convert) "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." The conversion logic is encapsulated within the LibConvert::convert function.

The LibConvert::convert functionality is implemented through a set of predefined conversion types, each supported by specific logic within the LibConvert library. However, the system lacks a dynamic mechanism to add support for new tokens once they are whitelisted, leading to a scenario where users cannot convert newly whitelisted tokens despite their valid status within the ecosystem.

Vulnerability Details

The vulnerability arises from the static implementation of conversion logic within the LibConvert library, which the ConvertFacet smart contract relies on. When a new token is whitelisted, the system does not automatically update to include conversion support for this token. The conversion process relies on a hardcoded set of conversion types, managed through the LibConvert library, which does not account for or adapt to the inclusion of new tokens without manual updates to the smart contract code.

ConvertFacet.sol
function convert(
bytes calldata convertData,
int96[] memory stems,
uint256[] memory amounts
)
external
payable
nonReentrant
returns (int96 toStem, uint256 fromAmount, uint256 toAmount, uint256 fromBdv, uint256 toBdv)
{
address toToken; address fromToken; uint256 grownStalk;
@> (toToken, fromToken, toAmount, fromAmount) = LibConvert.convert(convertData);
require(fromAmount > 0, "Convert: From amount is 0.");
require(fromAmount > 0, "Convert: From amount is 0.");
LibSilo._mow(msg.sender, fromToken);
LibSilo._mow(msg.sender, toToken);
(grownStalk, fromBdv) = _withdrawTokens(
fromToken,
stems,
amounts,
fromAmount
);
// calculate the bdv of the new deposit
uint256 newBdv = LibTokenSilo.beanDenominatedValue(toToken, toAmount);
toBdv = newBdv > fromBdv ? newBdv : fromBdv;
toStem = _depositTokensForConvert(toToken, toAmount, toBdv, grownStalk);
emit Convert(msg.sender, fromToken, toToken, fromAmount, toAmount);
}
LibConvert.sol
function convert(bytes calldata convertData)
external
returns (
address tokenOut,
address tokenIn,
uint256 amountOut,
uint256 amountIn
)
{
@> LibConvertData.ConvertKind kind = convertData.convertKind();
// if (kind == LibConvertData.ConvertKind.BEANS_TO_CURVE_LP) {
// (tokenOut, tokenIn, amountOut, amountIn) = LibCurveConvert
// .convertBeansToLP(convertData);
@> if (kind == LibConvertData.ConvertKind.CURVE_LP_TO_BEANS) {
(tokenOut, tokenIn, amountOut, amountIn) = LibCurveConvert
.convertLPToBeans(convertData);
@> } else if (kind == LibConvertData.ConvertKind.UNRIPE_BEANS_TO_UNRIPE_LP) {
(tokenOut, tokenIn, amountOut, amountIn) = LibUnripeConvert
.convertBeansToLP(convertData);
@> } else if (kind == LibConvertData.ConvertKind.UNRIPE_LP_TO_UNRIPE_BEANS) {
(tokenOut, tokenIn, amountOut, amountIn) = LibUnripeConvert
.convertLPToBeans(convertData);
@> } else if (kind == LibConvertData.ConvertKind.LAMBDA_LAMBDA) {
(tokenOut, tokenIn, amountOut, amountIn) = LibLambdaConvert
.convert(convertData);
@> } else if (kind == LibConvertData.ConvertKind.BEANS_TO_WELL_LP) {
(tokenOut, tokenIn, amountOut, amountIn) = LibWellConvert
.convertBeansToLP(convertData);
@> } else if (kind == LibConvertData.ConvertKind.WELL_LP_TO_BEANS) {
(tokenOut, tokenIn, amountOut, amountIn) = LibWellConvert
.convertLPToBeans(convertData);
@> } else if (kind == LibConvertData.ConvertKind.UNRIPE_TO_RIPE) {
(tokenOut, tokenIn, amountOut, amountIn) = LibChopConvert
.convertUnripeToRipe(convertData);
@> } else {
revert("Convert: Invalid payload");
}
}
LibConvertData.sol
@> enum ConvertKind {
BEANS_TO_CURVE_LP,
CURVE_LP_TO_BEANS,
UNRIPE_BEANS_TO_UNRIPE_LP,
UNRIPE_LP_TO_UNRIPE_BEANS,
LAMBDA_LAMBDA,
BEANS_TO_WELL_LP,
WELL_LP_TO_BEANS,
UNRIPE_TO_RIPE
}
/// @notice Decoder for the Convert Enum
@> function convertKind(bytes memory self)
internal
pure
returns (ConvertKind)
{
return abi.decode(self, (ConvertKind));
}

Impact

The users expecting to convert newly whitelisted tokens will encounter failed transactions, leading to confusion and waste gas (aka money) on failed transactions.
The ecosystem's dynamism and scalability are hindered as new tokens, despite being officially whitelisted and recognized by the system, cannot participate in conversion processes.

Tools Used

Manual review

Recommendations

To mitigate this issue is suggested to implement mechanisms to notify users when the new tokens become supported for conversion and update the LibConvert library and the ConvertFacet contract to provide informative and specific error messages for unsupported conversion attempts.

Updates

Lead Judging Commences

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

Informational/Invalid

kiteweb3 Submitter
over 1 year ago
giovannidisiena Lead Judge
over 1 year ago
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.