Closed c4-bot-10 closed 6 months ago
0xRobocop marked the issue as sufficient quality report
0xRobocop marked the issue as primary issue
enthusiastmartin (sponsor) disputed
Although you can make the reserve of asset 1, it does not show that there is an issue with that.
The PoC shows that it is possible to end up in a state where the reserve of an asset is 1. However, it is not shown that this will lead to any problems in the system. The comment in calculate_d_internal
only states that adding two is sufficient for rounding errors when the reserves are > 1, it does not say anything about the potential system impacts otherwise.
OpenCoreCH marked the issue as unsatisfactory: Insufficient proof
Lines of code
https://github.com/code-423n4/2024-02-hydradx/blob/main/HydraDX-node/math/src/stableswap/math.rs#L498-L503
Vulnerability details
Bug Description
The StableSwap invariant D is used to calculate the amount of shares as well as the tokens returned on swaps. The HydraDx Stableswap deviates from the original whitepaper implementation by adding 2 to the invariant to account for rounding errors. The changed functionality is also described in a comment.
Unfortunately, as the
MinPoolLiquidity
is only enforced on the shares of a pool, but not the single reserves, trades can lead to a pool where there is only 1 token of an asset left. This will lead to an incorrect calculation of D, which can result in losses to the users. An example where this, lower than intended D, could lead to issues is on deposits. On a deposit of liquidity, the process is as follows:One can see that this can lead to issues, if in the current reserve, one of the reserves is 1. In that case the oldD would be smaller than intended, while the newD, where the reserves of all are above 1, would be calculated correctly. This way the user depositing liquidity would receive more shares than intended. This would allow for the following attack path:
Impact
The issue allows a malicious user to push the pool into a state where he will receive more shares on his deposit of liquidity than intended.It needs to be mentioned that this only works on a pool with a current fee of 0%. As the fee can be set by the Authority for each pool and can be in the range between 0-100% this can be considered a valid state of a pool.
Proof of Concept
The following POC showcases an example of a user pushing the pool into the unintended state:
The file can be added to
pallets/stableswap/src/test/remove_liquidity.rs
Tools Used
Manual Review
Recommended Mitigation Steps
The issue can be mitigated by enforcing that reserves of all assets should never fall below 2. This must be enforced on every swap and on each withdrawal of liquidity.
Assessed type
Math