Summary
No tokens are received when withdrawing from an OperatorStakingPool
.
Vulnerability Details
Authorized operators may deposit into the OperatorStakingPool
by transferring LST tokens:
* @notice ERC677 implementation to receive deposits
* @param _sender address of sender
* @param _value amount of tokens to deposit
**/
function onTokenTransfer(address _sender, uint256 _value, bytes calldata) external {
if (msg.sender != address(lst)) revert InvalidToken();
if (!isOperator(_sender)) revert SenderNotAuthorized();
if (getOperatorStaked(_sender) + _value > depositLimit) revert ExceedsDepositLimit();
uint256 sharesAmount = lst.getSharesByStake(_value);
shareBalances[_sender] += sharesAmount;
totalShares += sharesAmount;
emit Deposit(_sender, _value, sharesAmount);
}
However, when authorized operators intend to withdraw from the pool, the tokens are not returned:
function withdraw(uint256 _amount) external {
if (!isOperator(msg.sender)) revert SenderNotAuthorized();
@> _withdraw(msg.sender, _amount);
}
https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/linkStaking/OperatorStakingPool.sol#L132C5-L135C6
function _withdraw(address _operator, uint256 _amount) private {
@> uint256 sharesAmount = lst.getSharesByStake(_amount);
@> shareBalances[_operator] -= sharesAmount;
@> totalShares -= sharesAmount;
@> emit Withdraw(_operator, _amount, sharesAmount);
}
https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/linkStaking/OperatorStakingPool.sol#L199C5-L205C6
As demonstrated, at no point is underlying LST returned to the rightful operator.
Impact
Stuck funds, irrecoverable loss of stake.
Tools Used
Manual Review
Recommendations
Transfer the owed tokens to a specified recipient
address at the end of the _withdraw
function.