Closed sherlock-admin closed 6 months ago
While TWAP is affected, this feature of the protocol is not a core feature of DODO itself. Additionally, TWAP features are deprecated, and will be removed by DODO in future iterations. Any external integrations would be out of scope of this contest. This has the similar root cause as #122, but the attack path described is insufficient to meet high severity.
Sponsor comments:
TWAP was designed in previous versions, but was abandoned before the function was developed. As a result, we don't have any use cases for TWAP, since we only provide view functions for TWAP(can view midPrice and BASE_PRICE_CUMULATIVELAST). Regardless of is_twap=true/false, it will not affect price calculations are used, since we don't have TWAP implementation. To prevent confusion, we will remove the related functions later.
osmanozdemir1
medium
A transaction leading a reserve to become zero will cause incorrect TWAP calculation
Summary
It is possible for a transaction to cause reserve of the
baseToken
or thequoteToken
to become 0. In that case, TWAP calculation will be incorrect.Vulnerability Detail
GSPVault::_twapUpdate()
function calculates TWAP price by calculating mid price and elapsed time if reserves are not zero.https://github.com/sherlock-audit/2023-12-dodo-gsp/blob/main/dodo-gassaving-pool/contracts/GasSavingPool/impl/GSPVault.sol#L86C2-L97C6
The reason for checking reserves are not zero is to prevent division by zero error in the getMidPrice() function (shown with arrows below).
Normally, in constant product AMM's, it is impossible to totally drain one of the tokens totally and make the balance 0 due to
x * y = k
formula. However, this protocol is not work like constant product AMM's. In this protocol, token reserves are calculated astoken balance - maintainer fee
.Thereby, it is possible to perform a huge selling action that results in a
token balance == maintainer fee
, which makes the reserve for that token to be equal to 0. Let's checksellBase
function._setReserve
function will be called after the selling action, and reserves for the quote token will be 0 if the remainingquote token balance == total mt fees
. The_setReserve
function will then call the _twapUpdate().As we mentioned above, the
_twapUpdate()
function will not update the cumulative price due to one of the reserves being 0._BASE_PRICE_CUMULATIVE_LAST_
parameter will not be updated, but the_BLOCK_TIMESTAMP_LAST_
parameter will be updated.So basically, the protocol will mistakenly interpret the TWAP as updated due to the last timestamp is changed, yet in truth, the TWAP remains unchanged as the associated function will not execute the
if block
.Note: The TWAP is not directly used in-scope contracts but it is updated in-scope contracts. I assume it is used in other parts of the protocol and an important element.
Impact
Code Snippet
https://github.com/sherlock-audit/2023-12-dodo-gsp/blob/main/dodo-gassaving-pool/contracts/GasSavingPool/impl/GSPVault.sol#L92C1-L96C49
Tool used
Manual Review
Recommendation
I am not sure what is the best solution for this issue but maybe disabling TWAP usage in case of a reserve becomes zero might be better than using incorrect TWAP prices. Setting
_IS_OPEN_TWAP_
to false when one of the reserves become 0, and adding an only admin function to open it again when reserves are filled up might work out.