Skip to content

Balancer swap#2290

Open
gztensor wants to merge 94 commits intodevnet-readyfrom
feat/balancer_swap
Open

Balancer swap#2290
gztensor wants to merge 94 commits intodevnet-readyfrom
feat/balancer_swap

Conversation

@gztensor
Copy link
Contributor

@gztensor gztensor commented Dec 15, 2025

Description

Implement PalSwap (similar to balancer swap) to replace Uniswap V3.

Unlike uniswap v2 or v3, it allows adding liquidity unproportionally to price. This is achieved by introducing the weights w1 and w2 so that w1 + w2 = 1. In these formulas x means base currency (alpha) and y means quote currency (tao). The w1 weight in the code is referred as weight_base, and w2 as weight_quote. Because of the w1 + w2 = 1 constraint, only weight_quote is stored, and weight_base is always calculated.

The formulas used for pool operation are following:

Price

p = (w1 * y) / (w2 * x)

Reserve deltas

(or -1 * payouts) in swaps are computed by

if ∆x is given (sell): ∆y = y * ((x / (x+∆x))^(w1/w2) - 1)
if ∆y is given (buy): ∆x = x * ((y / (y+∆y))^(w2/w1) - 1)

Limit orders

When swaps are executing the orders with slippage control, we need to know what amount we can swap before the price reaches the limit value of p':

If p' < p (sell): ∆x = x * ((p / p')^w2 - 1)
If p' < p (buy): ∆y = y * ((p' / p)^w1 - 1)

Swap initialization

In order to initialize weights with existing reserve values and price (for existing subnets):

w1 = px / (px + y)
w2 = y / (px + y)

Injection

Weights are adjusted when some amounts are added to the reserves. This prevents price from changing.

new_w1 = p * (x + ∆x) / (p * (x + ∆x) + y + ∆y)
new_w2 = (y + ∆y) / (p * (x + ∆x) + y + ∆y)

User Liquidity

The user liquidity stays disabled for now. The last commit # where all comments about user liquidity and tests (commented out) are present: fb0017f , diff it with 4e21da2 to see the user liquidity code.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

Breaking Change

This PR changes the following externally accessible entities:

  • add_liqudiity extrinsic: Remove tick_low and tick_high parameters.
  • Positions map is replaced with PositionsV2 map
  • Following state maps removed:
    • AlphaSqrtPrice
    • CurrentLiquidity
    • CurrentTick
    • FeeGlobalTao
    • FeeGlobalAlpha
    • ScrapReservoirTao (applied before removing)
    • ScrapReservoirAlpha (applied before removing)
    • Ticks
    • SwapV3Initialized
    • TickIndexBitmapWords

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have run ./scripts/fix_rust.sh to ensure my code is formatted and linted correctly
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@gztensor gztensor changed the title Feat/balancer swap Balancer swap Jan 28, 2026
Copy link
Collaborator

@shamil-gadelshin shamil-gadelshin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Are we sure that the next PR will restore user liquidity? We left a lot of code comments that make the code harder to read.

@basfroman
Copy link
Collaborator

basfroman commented Jan 31, 2026

Hey @gztensor, we are already preparing changes for SDK and btcli related to this PR.

But, also, we would like to clarify whether it is possible to implement two additional related functionalities for clients within current PR:

  • SwapRuntimeApi.get_subnet_prices - to return the prices of all subnets (similar to SwapRuntimeApi.get_subnet_price)
  • A way through which we can calculate slippage without doing a sim_swap call to the chain. Something in SubnetInfoRuntimeApi.get_dynamic_info and SubnetInfoRuntimeApi.get_all_dynamic_info to replace existing Uniswap logic

If you have any questions, please feel free to let us know and we will be happy to discuss them at the meeting.

sam0x17
sam0x17 previously approved these changes Feb 4, 2026
sam0x17
sam0x17 previously approved these changes Feb 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-cargo-audit This PR fails cargo audit but needs to be merged anyway

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants