Open sherlock-admin opened 1 year ago
Escalate
Given that:
- All amounts are of precision 18 decimals and multiplication before division rule is implemented
- Multiple checks on locked amounts wrt quantity opened: https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/PartyA/PartyAFacetImpl.sol#L50-L65
The amounts remaining locked are very small (magnitude of few wei per call), this issue should be of low severity per sherlock standards
You've deleted an escalation for this issue.
Escalate
Escalate
Given that:
- All amounts are of precision 18 decimals and multiplication before division rule is implemented
- Multiple checks on locked amounts wrt quantity opened: https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/PartyA/PartyAFacetImpl.sol#L50-L65
The amounts remaining locked are very small (magnitude of few wei per call), this issue should be of low severity per sherlock standards
Regarding the second bullet point, the checks will only be relevant if the position is fully closed via the forceClosePosition
or emergencyClosePosition
function, as they are forced to close the entire quantity of the position. However, if the position is partially filled via the fillCloseRequest
, the error might still occur since the caller can specify an arbitrary filledAmount
.
If an account has only traded a few times and the error only happens a few times, it might be fine. However, this is a trading protocol, and it is expected that there will be users who are active traders or entities that perform high-frequency or algorithmic trading.
Thus, the error will eventually accumulate into a significant value for these types of traders, and they will suffer the consequences as mentioned in my impact section of the report. In addition, it breaks an important protocol invariant where the locked balance does not decrease when a position is closed, which is unacceptable.
Escalate
Escalate
Given that:
- All amounts are of precision 18 decimals and multiplication before division rule is implemented
- Multiple checks on locked amounts wrt quantity opened: https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/facets/PartyA/PartyAFacetImpl.sol#L50-L65
The amounts remaining locked are very small (magnitude of few wei per call), this issue should be of low severity per sherlock standards
Regarding the second bullet point, the checks will only be relevant if the position is fully closed via the
forceClosePosition
oremergencyClosePosition
function, as they are forced to close the entire quantity of the position. However, if the position is partially filled via thefillCloseRequest
, the error might still occur since the caller can specify an arbitraryfilledAmount
.If an account has only traded a few times and the error only happens a few times, it might be fine. However, this is a trading protocol, and it is expected that there will be users who are active traders or entities that perform high-frequency or algorithmic trading.
Thus, the error will eventually accumulate into a significant value for these types of traders, and they will suffer the consequences as mentioned in my impact section of the report. In addition, it breaks an important protocol invariant where the locked balance does not decrease when a position is closed, which is unacceptable.
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.
Escalate
This issue is invalid because LibQuote.quoteOpenAmount(quote))
is defined as:
function quoteOpenAmount(Quote storage quote) internal view returns (uint256) {
return quote.quantity - quote.closedAmount;
}
in the closeQuote
function, quote.closedAmount
is also updated as follows:
quote.closedAmount += filledAmount;
Which means that when the user closes the position completely filledAmount == LibQuote.quoteOpenAmount(quote))
(which also means filledAmount/LibQuote.quoteOpenAmount(quote)) == 1
and without rounding error) and the whole amount is unlocked in any case
Escalate
This issue is invalid because
LibQuote.quoteOpenAmount(quote))
is defined as:function quoteOpenAmount(Quote storage quote) internal view returns (uint256) { return quote.quantity - quote.closedAmount; }
in the
closeQuote
function,quote.closedAmount
is also updated as follows:quote.closedAmount += filledAmount;
Which means that when the user closes the position completely
filledAmount == LibQuote.quoteOpenAmount(quote))
(which also meansfilledAmount/LibQuote.quoteOpenAmount(quote)) == 1
and without rounding error) and the whole amount is unlocked in any case
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.
@xiaoming9090 any comment on the escalation by @SergeKireev ?
Fixed code PR link: https://github.com/SYMM-IO/symmio-core/pull/24
Escalate
This issue is invalid because
LibQuote.quoteOpenAmount(quote))
is defined as:function quoteOpenAmount(Quote storage quote) internal view returns (uint256) { return quote.quantity - quote.closedAmount; }
in the
closeQuote
function,quote.closedAmount
is also updated as follows:quote.closedAmount += filledAmount;
Which means that when the user closes the position completely
filledAmount == LibQuote.quoteOpenAmount(quote))
(which also meansfilledAmount/LibQuote.quoteOpenAmount(quote)) == 1
and without rounding error) and the whole amount is unlocked in any case
Disagree. This does not make the issue invalid. If the trader executes many small partial closes without completely closing the position, the accumulated error in the locked values will exist. It is unacceptable for the protocol to have inaccurate locked values at any single point in time. The locked values are used to determine many crucial decisions throughout the protocol, such as in assessing the solvency of an account.
Result: Medium Has duplicates Agree with the fix and the comment here: https://github.com/sherlock-audit/2023-06-symmetrical-judging/issues/251#issuecomment-1685574052 maintaining severity as is
Escalations have been resolved successfully!
Escalation status:
xiaoming90
medium
Rounding error when closing quote
Summary
Rounding errors could occur if the provided
filledAmount
is too small, resulting in the locked balance of an account remains the same even though a certain amount of the position has been closed.Vulnerability Detail
https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/libraries/LibQuote.sol#L155
In Lines 157, 159, and 161 above, a malicious user could make the numerator smaller than the denominator (
LibQuote.quoteOpenAmount(quote)
), and the result will be zero due to a rounding error in Solidity.In this case, the
quote.lockedValues
will not decrease and will remain the same. As a result, the locked balance of the account will remain the same even though a certain amount of the position has been closed. This could cause the account's locked balance to be higher than expected, and the errors will accumulate if it happens many times.Impact
When an account's locked balances are higher than expected, their available balance will be lower than expected. The available balance affects the amount that users can withdraw from their accounts. The "silent" increase in their locked values means that the amount that users can withdraw becomes lesser over time, and these amounts are lost due to the errors.
Code Snippet
https://github.com/sherlock-audit/2023-06-symmetrical/blob/main/symmio-core/contracts/libraries/LibQuote.sol#L155
Tool used
Manual Review
Recommendation
When the
((quote.lockedValues.cva * filledAmount) / (LibQuote.quoteOpenAmount(quote)))
rounds down to zero, this means that a rounding error has occurred as the numerator is smaller than the denominator. The CVA,filledAmount
or both might be too small.Consider performing input validation against the
filledAmount
within thefillCloseRequest
function to ensure that the provided values are sufficiently large and will not result in a rounding error.