Liquid Staking

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

`OperatorVault#exitVault()` misses to call `updateDeposits()`

Summary

According to natspec of OperatorVault#exitVault() :

updateDeposits must be called before calling this function

However, it's not enforced in OperatorVCS#removeVault(), which is a public function that anyone can call, making vault to have its funds transferred to wrong address.

Vulnerability Details

Let's start with the natspec:

/**
* @notice Withdraws tokens from the Chainlink staking contract and sends them to the vault controller
@> * @dev updateDeposits must be called before calling this function
* @dev used to withdraw remaining principal and rewards after operator has been removed
* @dev will also send any unclaimed operator rewards to rewards receiver
* @return total principal withdrawn
* @return total rewards withdrawn
*/
function exitVault() external onlyVaultController returns (uint256, uint256) {

However, in function OperatorVCS#removeVault(), OperatorVault#updateDeposits() is not called before exiting vault:

/**
* @notice Removes a vault that has been queued for removal
* @param _queueIndex index of vault in removal queue
*/
function removeVault(uint256 _queueIndex) public {
address vault = vaultsToRemove[_queueIndex];
vaultsToRemove[_queueIndex] = vaultsToRemove[vaultsToRemove.length - 1];
vaultsToRemove.pop();
_updateStrategyRewards();
@> (uint256 principalWithdrawn, uint256 rewardsWithdrawn) = IOperatorVault(vault).exitVault();

Impact

Sending removed vault funds to wrong address.

Tools Used

Manual review

Recommendations

Create internal function _updateDeposits() having updateDeposits() function body, make both updateDeposits() and exitVault() call it:

Contract: OperatorVault.sol
- function exitVault() external onlyVaultController returns (uint256, uint256) {
+ function exitVault(uint256 _minRewards, address _rewardsReceiver) external onlyVaultController returns (uint256, uint256) {
+ _updateDeposits(_minRewards, _rewardsReceiver);
if (!isRemoved()) revert OperatorNotRemoved();
uint256 opRewards = getUnclaimedRewards();
if (opRewards != 0) _withdrawRewards();
Updates

Lead Judging Commences

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

[INVALID] `exitVault` doesn't call `updateDeposits` before calling `_withdrawRewards` in the vault removal process

Appeal created

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

[INVALID] `exitVault` doesn't call `updateDeposits` before calling `_withdrawRewards` in the vault removal process

Support

FAQs

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