Vault._state.liquidity.totalDeposit can avoid being decreased.
Summary
Vault._state.liquidity.totalDeposit is used as total deposit amount of baseToken in Vault.sol, when user deposits into Vault.sol, it will be increased, and when users withdraws it will be decreased.
In current implementation, there is a code path that a user can withdraw token from the vault without decreasing Vault._state.liquidity.totalDeposit.
In Vault.sol#L507, withdrawDepositEquivalent is calculated as uint256 withdrawDepositEquivalent = (userDeposits * shares) / userShares;
And in Vault.sol#L502, userDeposits is assigned by depositReceipt.cumulativeAmount
So if depositReceipt.cumulativeAmount is 0, withdrawDepositEquivalent will be 0, and _state.liquidity.totalDeposit will keep unchanged after Vault.sol#L509
It's doable by:
Alice call Vault.redeem to withdraw some token, during Vault._redeem, some ERC20 will be transferred to Alice
Alice transfers the ERC20 token to Bob(who is never interact with the Vault before)
jasonxiale
medium
Vault._state.liquidity.totalDeposit
can avoid being decreased.Summary
Vault._state.liquidity.totalDeposit
is used as total deposit amount ofbaseToken
inVault.sol
, when user deposits intoVault.sol
, it will be increased, and when users withdraws it will be decreased. In current implementation, there is a code path that a user can withdraw token from the vault without decreasingVault._state.liquidity.totalDeposit
.Vulnerability Detail
When user calls
Vault.redeem
, the function will transfer ERC20 token to the caller. And when the user callsVault.initiateWithdraw
, Vault._initiateWithdraw will update _state.liquidity.totalDepositIn Vault.sol#L507,
withdrawDepositEquivalent
is calculated asuint256 withdrawDepositEquivalent = (userDeposits * shares) / userShares;
And in Vault.sol#L502,
userDeposits
is assigned bydepositReceipt.cumulativeAmount
So ifdepositReceipt.cumulativeAmount
is 0,withdrawDepositEquivalent
will be 0, and_state.liquidity.totalDeposit
will keep unchanged after Vault.sol#L509It's doable by:
Vault.redeem
to withdraw some token, duringVault._redeem
, some ERC20 will be transferred to AliceVault.initiateWithdraw
to withdraw the baseToken, in such case, because of depositReceipt is zero, userDepositswill be zero, and leaving _state.liquidity.totalDeposit unchanged.Vault.completeWithdraw
to withdraw the tokenAfter the call, Bob will receives all the asset he deserves, but leaving
_state.liquidity.totalDeposit
unchanged.For POC, add the following code to
unit/Vault.user.t.sol
and runforge test --mc VaultUserTest --mt testTransferCompleteWithdraw -vv
Impact
By abusing this method, Vault will handle less
baseToken
than expectedCode Snippet
https://github.com/sherlock-audit/2024-02-smilee-finance/blob/3241f1bf0c8e951a41dd2e51997f64ef3ec017bd/smilee-v2-contracts/src/Vault.sol#L500-L510
Tool used
Manual Review
Recommendation
Maybe we can revert in
Vault.transfer/transferFrom
Duplicate of #39