-
Notifications
You must be signed in to change notification settings - Fork 7
Sulpiride - Precision loss in getUserQuota
#74
Comments
Escalate for 10 USDC I believe this issue is not a duplicate of #45 or of any other duplicate of that issue. #45 refers to the loss of precision in However the issue that I described is regarding the design of the quota management in D3UserQuota contract which at best leads to a incorrect quota calculation and at worst allows users to deposit more than they should. I believe this issue should a unique high |
You've created a valid escalation! To remove the escalation from consideration: Delete your comment. You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final. |
@marie-fourier
|
It seems like the precision loss is minimal too and the requirements for it are also quite strict |
Result: |
Escalations have been resolved successfully! Escalation status:
|
Sulpiride
high
Precision loss in
getUserQuota
Summary
In D3UserQuota contract, there's a precision loss in
getUserQuota
function that results in incorrect user quotaVulnerability Detail
In D3UserQuota contract,
quotaTokenAmount
holds the amount of tokens a user can deposit, depending on the amount of DODO tokens that user has, in terms of USD. ButquotaTokenAmount
is denominated in integers without fractionals parts and it results in a precision loss in certain scenarios and in incorrect calculation of a user's used quota.Let's take a real example from the deployed DODOv3 contracts on Goerli:
D3Oracle: https://goerli.etherscan.io/address/0xE4b90C582B9597A4EFF505fa11B8254495b54F9d
DAI token: 0x5e2C68Fd294a28b054565b8D3a764E5cbF8c58D6 (decimals = 18)
D3UserQuota.quotaTokenAmount
fetches the price of an asset by callingD3Oracle.getOriginalPrice
. Calling this on DAI returns this:tokenPrice =
99980000
($0.9998, slighthly less than 1 USD)priceDecimal =
8
Quota used for a given asset is calculated with this formula:
tokenBalance * tokenPrice / 10 ** (priceDecimal+tokenDecimals)
But if the tokenBalance is less than
10 ** tokenDecimals
and tokenPrice is less than10 ** priceDecimal
(less than 1 USD), the result of this formula will be 0:tokenBalance * tokenPrice / 10 ** (priceDecimal+tokenDecimals) = 9e17 * 99980000 / 10 ** (8 + 18) = 0
This may be expected behaviour since a depositor really tried to deposit less than 1 USD worth of asset and trying to repeat such transaction will make the tokenBalance greater than
10 ** tokenDecimals
.However a bug arrises when there are 2 such assets.
POC:
Prepare the environment:
In
test\TestContext.t.sol
change token decimals to simulate behaviour of DAI in Goerli:POC:
Add this in
test\DODOV3MM\D3Vault\periphery\D3UserQuota.t.sol
:Output of this function:
User quota stayed the same despite that we deposited ~$1.6 worth of assets.
Impact
Users will be able to deposit more than the protocol allows them.
Code Snippet
https://github.com/sherlock-audit/2023-06-dodo/blob/main/new-dodo-v3/contracts/DODOV3MM/D3Vault/periphery/D3UserQuota.sol#L82
https://github.com/sherlock-audit/2023-06-dodo/blob/main/new-dodo-v3/contracts/DODOV3MM/D3Vault/periphery/D3UserQuota.sol#L19-L23
Tool used
Manual Review
Recommendation
Use decimals with fractional parts in
quotaTokenAmount
andDecimalMath
library to calculate used quota of a userThe text was updated successfully, but these errors were encountered: