Submitted by kenzo, also found by PP1004, pedroais, and CertoraInc
The fee is wrongly accounted for in previewWithdraw.
Function returns wrong result;
Additionally, withdraw(assets,to,from) will always revert. (The user can still withdraw his assets via other functions).
The previewWithdraw function returns less shares than the required assets (notice the substraction):
This wont work, because if the user wants to receive amount of assets, he needs to burn more shares than that to account for the fee. Not less.
This will also make withdraw(assets,to,from) revert, because it takes the amount of shares from previewWithdraw, and then checks how much assets were really sent to the user, and verifies that its at least how much he asked for:
But since the expectedShares is smaller than the original amount, and since _withdraw deducts the fee from expectedShares, then always assets > assetsReceived, and the function will revert.
The amount of shares that previewWithdraw should return is:
convertToShares(assets.add(assets.mul(feeBPS).div((10000.sub(feeBPS))))
I prove this mathematically in this image.
bghughes (Rubicon) confirmed 
HickupHH3 (judge) commented:
bghughes (Rubicon) commented:
bghughes (Rubicon) commented:
