Submitted by carrotsmuggler, also found by oakcobalt
/contracts/pool-manager/src/helpers.rs#L437-L438
The provide_liquidity function is used to add liquidity to the dex pools. This function implements a slippage tolerance check via the assert_slippage_tolerance function.
This function implements slippage tolerance in two sub-functions, one for stableswap and one for constant product. This function basically compares the ratio of liquidity of the deposit to the ratio of pool liquidity.
For the constant product pool, the slippage tolerance checks both the 1/0 ratio and 0/1 ratios, where 0 and 1 represent the two tokens of the pool.
But for stableswap, it only does a one-sided check.
The situation is best described for the scenario where slippage_tolerance is set to 0. This means the pool should ONLY accept liquidity in the ratio of the pool liquidity. This is enforced for constant product pools correctly. However, for stableswap pools, this is incorrect.
If slippage_tolerance is set to 0, then one_minus_slippage_tolerance is 1. Thus, the inequality check above makes sure that the pool_ratio is always less than or equal to the deposit_ratio for the transaction to go through. However, the deposit_ratio can be be either higher or lower than than the pool_ratio, depending on the components of the liquidity addition. The inequality above only checks for one case (less than equals) and misses the other check (greater than equals).
This means even with slippage_tolerance set to 0, the stableswap pool will accept liquidity that is not in the ratio of the pool liquidity.
Furthermore, for the case where the deposit_ratio is higher than the pool_ratio, there is no slippage restriction on the pool at all.
The entire reason slippage_tolerance exists, is so that the user can specify the exact amount of lp tokens they expect out of the pool. However, the protocol does not implement a minimum_amount_out like on curve, and instead uses this slippage_tolerance value. This means the slippage_tolerance value is crucial to ensure that the depositor is not leaking any value. However, below shown is a situation where if the depositor adds liquidity in certain compositions, they can leak any amount of value.
A POC is run to generate the numbers given here.
Lets say a pool is created and liquidity is provided with 1e6 whale and 2e6 luna tokens. It is quite common to have stableswap pools similarly imbalanced, so this is a usual scenario. Now a user deposits 1e4 whale and 1e5 luna tokens in this pool.
At the end, the pool composition becomes 1.01e6 whale and 2.1e6 luna tokens. The initial liquidity addition created 2997146 lp tokens and the second liquidity addition creates 109702 lp tokens, for a total of 3106848 lp tokens.
These numbers come from running the POC below, which has the output:
So during the slippage check on the second deposit, pool_sum = 1e6+2e6 + 1e5+1e4 = 3.11e6, and the deposit_sum = 1e5+1e4 = 1.1e5.
pool_ratio = 3.11e6/3106848 = 1.001014533
deposit_ratio = 1.1e5/109702 =1.00271645
Now, even if slippagetolerance is set to 0, since `poolratio<deposit_ratio, the transaction goes through. However, the issue is that in the second liquidity addition, the user could have received less than109702` lp tokens and the transaction would have still gone through.
Say the user receives only 108000 tokens. Then, total pool lp_tokens = 2997146+108000 = 3105146
pool_ratio = 3.11e6/3105146 = 1.001563212 
deposit_ratio = 1.1e5/108000 = 1.018518519
This transaction will also pass, since deposit_ratio > pool_ratio. However, we can clearly see that the liquidity depositor has lost 1.55% of their deposit. So even with slippage_tolerance set to 0, the stableswap pool can accept liquidity that is not in the ratio of the pool liquidity, and depositors can eat large amounts of slippage.
A POC was used to generate the results of the liquidity addition. First, a couple helper functions,
The actual POC to generate the numbers.
For stableswap, the slippage_tolerance should be checked against the difference in the price ratios, so abs(pool_ratio - deposit_ratio). This way both sides of the inequality are checked.
jvr0x (MANTRA) confirmed
