hats-finance / StakeWise-0xd91cd6ed6c9a112fdc112b1a3c66e47697f522cd

Liquid staking protocol for Ethereum
Other
0 stars 0 forks source link

Inaccuracy of share price calculation when depositing which causes unfairness #35

Open hats-bug-reporter[bot] opened 1 year ago

hats-bug-reporter[bot] commented 1 year ago

Github username: @koolexcrypto Submission hash (on-chain): 0x6c3df3b22dba0a43196420ab376acaa349eae6d70a7f87fcf3b800fb885e6bb2 Severity: high

Description:

Description

_deposit method is used to process user deposits. The user deposits ETH and receives shares. The received shares is calculated (with rounding up) as follows: shares = assets * totalShares / _totalAssets

This is done by calling _convertToShares

    // calculate amount of shares to mint
    shares = _convertToShares(assets, Math.Rounding.Up);

Code link

Please note that before calculating the amount of shares, _checkHarvested is called to check whether the vault is harvested.

  function _deposit(
    address to,
    uint256 assets,
    address referrer
  ) internal virtual returns (uint256 shares) {
    _checkHarvested();

Code link

This is to ensure an accurate and fair price of the share before the deposit as _totalAssets and _totalShares are likely to be updated when harvesting. However, _totalAssets and _totalShares could possibly be updated when updating the exit queue and there is no check if the exist queue can be updated. Therefore, the share price could possibly be inaccurate which is unfair. The only case where the issue doesn't occur is when calling updateStateAndDeposit. Otherwise, all deposits that come via calling deposit or by sending ETH directly to the contract (which triggers the fallback that calls _deposit) are vulnerable to inaccurate share price.

Attack Scenario

Attachments

  1. Proof of Concept (PoC)

Code link

Note: I've set the severity to high due to the fact that exist queue shares could be big within 24 hours. Therefore, causing unfairness in the protocol that's non-negligible.

Recommend mitigation

In _deposit, call _updateExitQueue if exist queue can be updated before any calculation of the amount of shares

An example:

if (canUpdateExitQueue()) {
  _updateExitQueue();
}
tsudmi commented 1 year ago

When exit queue update is called it decreases _totalAssets and _totalShares proportionally, so it shouldn't affect the conversion rate. It's like someone withdraws before you deposit, the rate should stay the same.