While calculating the stableCoinLossNumerator on L833, lastStableCoinLossErrorOffset is subtracted due to the fact that the result of stableCoinLossPerUnitStaked is rounded up, but lastStableCoinLossErrorOffset being scaled to 1e18 precision can lead to underflows for vaults with low borrowed amount, thus making the vault non-liquidatable and yielding underwater debt for the protocol. This opens the door for malicious users to grief the protocol by opening really small positions.
/* code */
if (_debtToOffset == _totalStableCoinDeposits) {
stableCoinLossPerUnitStaked = DECIMAL_PRECISION; // When the Pool depletes to 0, so does each deposit
lastStableCoinLossErrorOffset = 0;
} else {
uint256 stableCoinLossNumerator = _debtToOffset *
@> DECIMAL_PRECISION - lastStableCoinLossErrorOffset; // @audit underflow
/*
* Add 1 to make error in quotient positive. We want "slightly too much" StableCoin loss,
* which ensures the error in any given compoundedStableCoinDeposit favors the Stability Pool.
*/
stableCoinLossPerUnitStaked =
stableCoinLossNumerator /
_totalStableCoinDeposits +
1;
lastStableCoinLossErrorOffset =
stableCoinLossPerUnitStaked *
_totalStableCoinDeposits -
stableCoinLossNumerator;
}
/* code */
Recommendation
Consider enforcing a minimum borrowable amount in VaultFactory::borrow()
To verify the issue, follow this guide and include this test in the codebase. The test demonstrates the impossibility of liquidating a vault with small debt.
Impact
Severity: Medium Likelihood: Medium
Context
StabilityPool::_computeRewardsPerUnitStaked()
Description
While calculating the
stableCoinLossNumerator
on L833,lastStableCoinLossErrorOffset
is subtracted due to the fact that the result ofstableCoinLossPerUnitStaked
is rounded up, butlastStableCoinLossErrorOffset
being scaled to 1e18 precision can lead to underflows for vaults with low borrowed amount, thus making the vault non-liquidatable and yielding underwater debt for the protocol. This opens the door for malicious users to grief the protocol by opening really small positions.Recommendation
Consider enforcing a minimum borrowable amount in
VaultFactory::borrow()
PoC
To verify the issue, follow this guide and include this test in the codebase. The test demonstrates the impossibility of liquidating a vault with small debt.