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

Users will lose all their LP tokens deposited in the Silo after migration

Summary

The migration will remove all the liquidity of WETH:Bean and convert it to WSETH:Bean. As is shown here, Beanstalk owns around 99.94% of the tokens:
https://etherscan.io/token/0xbea0e11282e2bb5893bece110cf199501e872bad#balances

This means that after migration is done, there won't be much liquidity in the WETH:Bean pool.

The problem is that all the deposits make in the Silo utilize the stem and the token to generate a depositId and link it to the account:

LibBytes.packAddressAndStem(token, stem);

Once the migration is done, users cannot withdraw their funds for the following reasons:

  • Users will try to withdraw their tokens with the old LP address(WETH:Bean) but the protocol will not have enough funds to return it as the funds have been migrated to a new pool.

  • If the users try to withdraw the funds using the new pool, it will generate a new depositId that has no funds added into it.

  • Converting funds also doesn't work as it will try to remove the LP tokens from the old pool before converting to Beans for instance, the call will revert.

Another problem is that migrating the funds to a new pool with a different exchange rate like WSETH:Bean, will also impact the amount of LP that represents user deposits, it will be different. So here we have two problems, even if the user would be able to withdraw his funds, it would be a different amount that does not represent what he deposited previously.

Vulnerability Details

LibTokenSilo -> addDepositToAccount

// add amount and bdv to the deposits.
s.a[account].deposits[depositId].amount = s.a[account].deposits[depositId].amount.add(
amount.toUint128()
);
s.a[account].deposits[depositId].bdv = s.a[account].deposits[depositId].bdv.add(
bdv.toUint128()
);

LibTokenSilo -> removeDepositFromAccount

function removeDepositFromAccount(
address account,
address token,
int96 stem,
uint256 amount
) internal returns (uint256 crateBDV) {
AppStorage storage s = LibAppStorage.diamondStorage();
uint256 depositId = LibBytes.packAddressAndStem(token, stem);
uint256 crateAmount = s.a[account].deposits[depositId].amount;
crateBDV = s.a[account].deposits[depositId].bdv;

Impact

  • The user will lose all the Well LP deposited in the Silo after the migration.

  • Protocol will lose the link between depositId and the new LP

  • Protocol does not have a correct value in s.a[account].deposits[depositId].amount that represents the user deposit.

  • User can no longer convert his tokens due to IWell(well).removeLiquidityOneToken fail as it will try to remove liquidity from the old pool that no longer has sufficient funds.

Tools Used

Hardhat & Manual Review

Recommendations

  • Deposit ID Mapping Contract: Create a migration process to map old depositIds to new depositIds. This process would store a mapping of old depositIds to new ones, ensuring that users can claim or interact with their deposits post-migration.

  • Migration Function: Implement a migration function that handles the transfer of user balances from the old LP to the new LP, updating the mapping as it goes. This function could be triggered by users themselves or run as a batch process of the protocol.

Updates

Lead Judging Commences

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

Support

FAQs

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