bcc-research / CFMMRouter.jl

Convex optimization for fun and profit. (Now in Julia!)
MIT License
315 stars 59 forks source link

Numerical Stability Challenges in Uniswap V3 and Curve Pools #29

Open liewmanchoi opened 1 week ago

liewmanchoi commented 1 week ago

Background

I am developing an optimization program that encounters numerical stability issues due to the large range of values in liquidity pools. For Uniswap V2-type pools, we have found that simply applying a proportional scaling to the reserve values of the same token effectively mitigates these numerical issues. This scaling transformation allows us to adjust the values into a more manageable range for computation without affecting the accuracy of the Uniswap V2 trading formula.

Previous discussions can be found at #11 #12 #22

Problem Description

However, this straightforward scaling method fails in Uniswap V3 and Curve-type pools due to their more complex trading formulas. Below, we detail the key differences and explain why the scaling approach that works for Uniswap V2 does not apply to these pools.

  1. Uniswap V3 Pools

    In Uniswap V3 pools, the trading formula is represented by the following equation:

    $$(R_1 + \alpha)(R_2 + \beta) = K$$

    where:

    • $R_1$ and $R_2$ are the reserves of two tokens in the pool,
    • $\alpha$ and $\beta$ are constants that define the price range or liquidity characteristics of the pool,
    • $K$ is a constant that represents the pool’s invariant.

    This equation maintains a product invariant with constants $\alpha$ and $\beta$, which are essential to controlling price ranges and liquidity in Uniswap V3. Proportionally scaling $R_1$ or $R_2$ independently disrupts this invariant relationship, leading to inaccuracies in trade calculations. As a result, the scaling method that works for Uniswap V2 is ineffective for Uniswap V3.

  2. Curve Pools

    Curve pools have a more complex formula to facilitate stable swaps between assets, designed to minimize slippage for assets of similar value. For a two-asset Curve pool, the full pricing formula is:

    $$A \cdot n^n \cdot \left( \sum_{i=1}^n Ri \right) + D = A \cdot n^n \cdot \sum{i=1}^n \frac{D}{n Ri} + \prod{i=1}^n R_i$$

    where:

    • $A$ is an amplification coefficient that adjusts the pool’s curve shape, promoting low slippage in stable swaps,
    • $n$ is the number of assets in the pool (e.g., 2 for a two-asset pool),
    • $R_i$ represents each asset’s reserve in the pool,
    • $D$ is the invariant representing the total liquidity in the pool.

    This equation is more intricate than those for Uniswap pools, as it involves both additive and multiplicative terms, which collectively define the invariant $D$ in terms of reserves $R_i$. Simple proportional scaling of any reserve disrupts the balance of these polynomial terms, causing inaccuracies in the calculated output amounts due to the breakdown of the invariant balance.

Request for Assistance

While our current approach addresses numerical stability for Uniswap V2 pools, it fails for Uniswap V3 and Curve pools due to their more intricate formulas. I seek guidance or recommendations on methods that can manage numerical stability in these more complex pool environments, ensuring the optimization algorithm is practical and accurate under real-world conditions.

Any insights or suggestions from the community would be greatly appreciated!

liewmanchoi commented 1 week ago

@tjdiamandis Sorry to bother you, but do you have any suggestions for this issue?

dzmitry-lahoda commented 1 week ago

I am not mathematician exactly nor algorithmic, but after tinkering for a while if feels this CFMMRouter and cfmm-routing-code (they use different math methods) seems is way approximately limit search space. There are some (hopefully) valid heuristics to limit input to these methods too. But after some relaxed possible space found, it seems brute force is ok, like next:

https://github.com/ComposableFi/composable-vm/blob/main/mantis/simulation/routers/oracles/bforacle.py (imagine it written in Rust for speed). (credit for this modification of BF is too https://github.com/LautaroLasorsa, and seems solution is based on this formulation of problem https://cs.stackexchange.com/questions/165350/optimization-of-value-over-network-flow-from-start-to-end-node-with-constant-fun)

Also afaik did not saw any paper on this,

If you have small assets, curve and univ3 looks for you very similar as univ2. If you have large amount of assets to swap - route finding becomes different. So there is not even one algorithm to rule them all.

dzmitry-lahoda commented 1 week ago

Also I know there is very active research on mixing discrete graph algorithms with continues numerical optimization methods (topologygraphs something something), so I do not have at hand anything to refer.

liewmanchoi commented 5 days ago

I am not mathematician exactly nor algorithmic, but after tinkering for a while if feels this CFMMRouter and cfmm-routing-code (they use different math methods) seems is way approximately limit search space. There are some (hopefully) valid heuristics to limit input to these methods too. But after some relaxed possible space found, it seems brute force is ok, like next:

ComposableFi/composable-vm@main/mantis/simulation/routers/oracles/bforacle.py (imagine it written in Rust for speed). (credit for this modification of BF is too @LautaroLasorsa, and seems solution is based on this formulation of problem cs.stackexchange.com/questions/165350/optimization-of-value-over-network-flow-from-start-to-end-node-with-constant-fun)

Also afaik did not saw any paper on this,

If you have small assets, curve and univ3 looks for you very similar as univ2. If you have large amount of assets to swap - route finding becomes different. So there is not even one algorithm to rule them all.

Hi, @dzmitry-lahoda. Thanks very much for your kind and detailed reply. After carefully reading the code and docs, I found that the proposed solution may only apply to the Uniswap-V2 pool because it will only scale the reserves of the liquidity pool (not including other pool state values). Is my opinion correct?

dzmitry-lahoda commented 3 days ago

Brute force can be applied to ANY curve(including non analytical), even to classical orderbook with whatever gas formation rules(just plug any formula(OB/UNIv3/Balancer/Curve + data instead of uniV2, there are plenty of python/rust examples on GH). More analytical solution a way harder((N)LP solvers or LBFGSB) to handle it as it seems. So up to some approximation UNIv3 may be approximation of others, so that need to be researched in what cases can approximate others with UNIv2 for presearch.