Closed c4-bot-10 closed 5 months ago
The report is of low quality, the mitigation it is the same code snippet from the one above.
0xRobocop marked the issue as insufficient quality report
0xRobocop marked the issue as primary issue
The report is of low quality, the mitigation it is the same code snippet from the one above.
@0xRobocop FYI, asset_out_state.reserve
--> reserve_no_fee
.
Based on the definition of MaxOutRatio
(Max fraction of asset reserve to buy in single transaction), it seems intended that the fees are not taken into account. Taking them into account would be an alternative design, but the report does not show why the current design / definition of the ratio leads to a problem -> QA
OpenCoreCH changed the severity to QA (Quality Assurance)
OpenCoreCH marked the issue as grade-b
Based on the definition of
MaxOutRatio
(Max fraction of asset reserve to buy in single transaction), it seems intended that the fees are not taken into account.
Hi @OpenCoreCH, thanks for the review. Yes, this is where the problem lies. I should have explained it more clearly: When we use MaxOutRatio
, the fees are intended to not be taken into account, but we used it with asset_out_state.reserve
, which includes the fees, leading to situations where more assets than MaxOutRatio
are taken out of the pool.
Give an example: asset.reserve
is 100, MaxOutRation
is 40%, and the asset fee is 20%, then the reserve will be split as 80:20 (check calculate_buy_for_hub_asset_state_changes
, it will split reserve as no_fees and fees). In the current situation, the max allowed amount
out will be 10040% = 40, then the fee is calculated as (40/80) 20 + 1 = 11. In the end, the assets taken out are (40/80) or (51/100) ~50%, which is bigger than 40% both for the assets not including the fees or as a whole. This can also lead to DoS if MaxOutRation
is bigger than the asset fee (not enough fees during the removal, but the parameters are controlled by the authority).
In short, the root cause is amount
provided by the user is the final amount taken out, but we apply it with MaxOutRatio
on the asset.reserve
which includes the fees, so more than MaxOutRatio
assets can be taken out of the pool in the end.
Ok, I think I see what you mean. Nevertheless keeping it as QA, as these differences are very small for a sufficiently large pool and even if more than MaxOutRatio
assets can be taken out, it is not clear / shown what the impact on the protocol will be.
Lines of code
https://github.com/code-423n4/2024-02-hydradx/blob/main/HydraDX-node/pallets/omnipool/src/lib.rs#L1858 https://github.com/code-423n4/2024-02-hydradx/blob/main/HydraDX-node/pallets/omnipool/src/lib.rs#L1179
Vulnerability details
Impact
More assets than
asset.reverse / MaxOutRatio
are taken out whenbuy_asset_for_hub_asset
orbuy
is called.Proof of Concept
In omnipool, we apply asset fees on trading. Especially, during trading, the asset reverse will be split into two parts: 1. Amount we can take out. 2. The asset fees. For example, in
pub fn calculate_buy_for_hub_asset_state_changes
:Let's say the
asset.reserve
is 100, and the asset fee is 20%, then the reserve will be split as 80:20. Ifasset_out_amount
is 10, then the fee will be (10/80) * 20 + 1 = 3.To prevent liquidity attacks, we restrict the max ration of input amount in buy functions:
However, the amount provided by the user is the final amount taken out from the pool, not including the fees. In the example above, the amount will be 10, and the actual output ratio will be 10/80 (or (10+3)/100), which is bigger than what we calculate as 10/100. So more ratio assets are taken out.
Tools Used
Manual review.
Recommended Mitigation Steps
Assessed type
Math