Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: high
Invalid

`WithdrawPool:deposit()` directly transfers the LST to `priorityPool` without converting it to `shares`

Summary

WithdrawPool:deposit() directly transfers the LST to priorityPool without converting it to shares

Vulnerability Details

When user deposits assetToken to the priorityPool, it deposits to the withdrawPool if any queuedWithdrawals. In return withdrawPool transfers the LST tokens to the priorityPool, which is then transfered to the user.

function _deposit(address _account, uint256 _amount, bool _shouldQueue, bytes[] memory _data) internal {
...
if (totalQueued == 0) {
uint256 queuedWithdrawals = withdrawalPool.getTotalQueuedWithdrawals();
if (queuedWithdrawals != 0) {
uint256 toDepositIntoQueue = toDeposit <= queuedWithdrawals ? toDeposit : queuedWithdrawals;
withdrawalPool.deposit(toDepositIntoQueue);
toDeposit -= toDepositIntoQueue;
@> IERC20Upgradeable(address(stakingPool)).safeTransfer(_account, toDepositIntoQueue);
}
...
}
function deposit(uint256 _amount) external onlyPriorityPool {
token.safeTransferFrom(msg.sender, address(this), _amount);
@> lst.safeTransfer(msg.sender, _amount);
_finalizeWithdrawals(_amount);
}

But the problem is, LST is directly transfered to priorityPool without converting the assetToken to shares value(see above code), which is then transfered to user.

Impact

As result, user will receive the same amount of shares as of deposited assetToken, which should not be because assetToken should be first converted to shares value & then transferred to priorityPool

Tools Used

Manual Review

Recommendations

Convert the assetToken amount in withdrawPool:deposit() before transferring to priorityPool.

function deposit(uint256 _amount) external onlyPriorityPool {
token.safeTransferFrom(msg.sender, address(this), _amount);
- lst.safeTransfer(msg.sender, _amount);
+ uint256 sharesToTransfer = _getSharesByStake(_amount);
+ lst.safeTransfer(msg.sender, sharesToTransfer);
_finalizeWithdrawals(_amount);
}

Also while transferring the LST to user in priorityPool:_deposit(), use initialBalance & finalBalance method to check the accurate amount of LST that is transfered to priorityPool and then transfer it to the user.

Updates

Lead Judging Commences

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

Support

FAQs

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