Closed sherlock-admin closed 6 months ago
1 comment(s) were left on this issue during the judging contest.
takarez commented:
invalid
I would like to see a PoC for this. The attack seems possible only if stableCollateralBalance or stableCollateralPerShareAfterSettlement is small but I am unsure one can reach this state without the protocol having been nuked (longs have gotten all the stableCollateral amount due to extreme price rise).
Yeah this appears to be for very small amounts. The MIN_DEPOSIT
is 1e6 for rETH stable deposit. Likewise, there are minimum amounts on margin for leverage trades.
Agree with sponsors, am doubtful of magnitude of loss given stableBalance
in 18 decimals is first scaled by another 18 decimals by multiplying by (10 ** decimals()))
(10 ** 18) first. So by that logic the example will be:
_collateralPerShare = 19e18 *1e18 / 10e18 = 19e18
xiaoming90
high
Deposit does not round in favor of the vault
Summary
When calculating how many shares/UNIT to be minted to a user for a certain amount of the collateral they deposit, it does not round in favor of the vault, leading to users getting more shares than expected.
Vulnerability Detail
The
stableCollateralPerShare
function computes the number of collaterals per share. Note that in Line 214, the calculation is rounded down. This means that if thestableBalance
is 19 andtotalSupply
is 10, the result will be 1 rETH/share in Solidity instead of 1.9 rETH/share if floating point is supported in other languages.https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/StableModule.sol#L214
When the
_collateralPerShare
result returned from thestableCollateralPerShare
function is rounded down, one share is worth fewer collateral tokens (rETH). Intuitively, this means that the share becomes cheaper. As such, you can receive more shares for a specific amount of assets you deposited since the price of each asset is now cheaper.The
stableCollateralPerShare
function is used within theexecuteDeposit
function to compute the price per share (PPS) to determine the number of shares/UNIT to be minted to the depositor. Since the PPS is rounded down (cheaper than expected)(e.g. 1 rETH per share instead of 1.9 rETH per share), this means that the depositor will get more shares/UNIT than expected. Thus, the vault rounds in favor of the users instead of itself.https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/StableModule.sol#L70
Assume that Bob deposits 20 rETH:
The above shows that the vault does not round in favor of itself.
Impact
As shown in the example above, users are getting more shares than expected (20 vs 10.5).
Code Snippet
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/StableModule.sol#L214
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/StableModule.sol#L70
Tool used
Manual Review
Recommendation
A rule of thumb when implementing a vault is to always round in favor of the vault instead of the users.
When calculating many shares/UNIT to be minted to a user for a certain amount of the collateral they deposit, it should always be rounded in favor of the vault instead of the users.
It is fine to use the existing
stableCollateralPerShare
for withdrawal, as rounding down means fewer assets per share, and the users will receive fewer assets in exchange for their shares/UNITs, thus favoring the vault.However, it is not unsafe to use the existing
stableCollateralPerShare
function for deposit, as it is rounding in favor of the users. The formula used for computing thestableCollateralPerShare
should be rounded up as follows (Assuming using Solmate's Math)