Liquid Staking

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

inconsistent share calculation

Summary

inconsistent share calculation

Vulnerability Details

The issue of Inconsistent Share Calculation in the OperatorStakingPool contract stems from how the contract handles the conversion between token amounts and shares during deposits and withdrawals. Let's break this down:

Deposit Process (in onTokenTransfer):

uint256 sharesAmount = lst.getSharesByStake(_value);````shareBalances[_sender] += sharesAmount;````totalShares += sharesAmount;

Withdrawal Process (in _withdraw):

uint256 sharesAmount = lst.getSharesByStake(_amount);````shareBalances[_operator] -= sharesAmount;````totalShares -= sharesAmount;

The problem here is that both functions use lst.getSharesByStake() to calculate shares, but they use it in different contexts:

  • For deposits, it's correct to use getSharesByStake() because you're converting incoming tokens to shares.

  • For withdrawals, using getSharesByStake() is problematic because you're trying to determine how many shares to burn based on the amount of tokens the user wants to withdraw.

The value of a share can change over time, especially if the underlying staking pool accrues rewards. Using getSharesByStake() for withdrawals assumes that the share price hasn't changed since the deposit, which is likely incorrect.

Impact

If the share value has increased, users could withdraw more tokens than they should be entitled to. Conversely, if the share value has decreased, users would receive fewer tokens than expected. Over time, this could lead to a situation where the contract's internal accounting of shares doesn't match the actual token balance it holds.

Tools Used

Manual review

Recommendations

function _withdraw(address _operator, uint256 _amount) private {
uint256 currentBalance = lst.getStakeByShares(shareBalances[_operator]);
require(_amount <= currentBalance, "Insufficient balance");

uint256 sharesToBurn = (_amount * shareBalances[_operator]) / currentBalance;
shareBalances[_operator] -= sharesToBurn;
totalShares -= sharesToBurn;
emit Withdraw(_operator, _amount, sharesToBurn);
lst.withdraw(_amount); // Assuming this function exists in the LST contract

}

Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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