# Stable swap pools

Tapp's stable swap pools are designed for assets that trade near a 1:1 price ratio—like two stablecoins or wrapped versions of the same token. They implement Curve-style math in the `stable::stable` module to achieve very low slippage.

This guide summarizes the Move code and explains how liquidity providers interact with these pools.

## Key data types

### Config

* `authority`: address allowed to modify global settings.
* `pending_authority`: temporary storage when transferring authority.
* `fee_tiers`: supported trading fees (0.01% and 0.05%).

### Pool

Each pool stores many fields:

```move
struct Pool has key, store {
    pool_addr: address,            // resource account for the pool
    n_coins: u64,                  // number of assets (2‒8)
    rate_multipliers: vector<u256>,// decimals normalization factors
    stored_balances: vector<u256>, // pool reserves
    fee: u256,                     // trade fee
    offpeg_fee_multiplier: u256,   // extra fee when off the peg
    initial_a: u256,               // A parameter at start of ramp
    future_a: u256,                // target A parameter
    initial_a_time: u64,           // ramp start time
    future_a_time: u64,            // ramp end time
    positions: BigOrderedMap<u64, Position>,
    position_index: u64,
    total_shares: u256,
}
```

### Position

A `Position` simply tracks a user's share count:

```move
struct Position has copy, drop, store {
    index: u64,
    shares: u256,
}
```

## Creating a pool

`create_pool(pool_signer, assets, assets_decimals, fee, rest_args, creator)` initializes a new resource account that holds the `Pool` struct. Arguments include:

* `assets`: vector of coin type addresses.
* `assets_decimals`: decimal places for each asset so reserves can be normalised.
* `fee`: must match a configured tier.
* `rest_args`: BCS-encoded `amp` (initial A factor) and `offpeg_fee_multiplier`.
* `creator`: recorded in the `PoolCreated` event.

Most other entry functions accept a `stream: &mut BCSStream` parameter that encodes additional arguments in Binary Canonical Serialization (BCS) format. This keeps the signatures short while allowing complex parameter lists.

Balances start at zero and `rate_multipliers` adjust each token to 36 decimals. The amplification factor `A` controls the curvature of the swap function and can later be adjusted through ramping operations.

## Adding liquidity

`add_liquidity(pool_signer, position_idx, stream, receiver)` accepts a `BCSStream` that encodes:

1. `amounts` – vector of deposit amounts (one per coin in the pool)
2. `min_mint_amount` – minimum LP tokens to mint

The function then:

1. Computes the current invariant `D` using `get_D_mem`.
2. Transfers tokens in and updates `stored_balances`.
3. Recalculates `D` and applies fees on any imbalance using a dynamic fee formula.
4. Mints pool shares proportional to the change in `D`.

If `position_idx` is `some`, the existing position receives the new shares. Otherwise a new index is created.

## Removing liquidity

`remove_liquidity(pool_signer, position_idx, stream, creator)` also expects a `BCSStream`. The first byte selects the withdrawal mode:

1. **Single coin withdrawal** – stream then carries `burn_amount`, `i` (coin index) and `min_received`.
2. **Imbalanced withdrawal** – followed by a vector `amounts` and `max_burn_amount`.
3. **Proportional withdrawal** – remaining bytes encode `burn_amount` and `min_amounts` for each coin.

* `ramp_a(stream)` – stream contains `future_a` (u256) and `future_a_time` (u64) to gradually change the amplification factor.
* `set_new_fee(stream)` – stream provides `new_fee` (u256) and `new_offpeg_fee_multiplier` (u256).

## Swapping tokens

`swap(pool_signer, stream, receiver)` reads the sold token index `i`, bought token index `j`, input amount `dx` and minimum output `min_dy`. It calculates normalized balances (`xp`), calls `internal_swap` to solve the stable swap invariant and applies a dynamic fee based on how far the trade moves the pool off the peg. Reserves are updated and a `Swapped` event is emitted.

## Pool operations

Administrative actions are routed through `run_pool_op`:

* `ramp_a(stream)` – gradually change the amplification factor between `initial_a` and `future_a` over time.
* `stop_ramp_a()` – freeze `A` at its current value.
* `set_new_fee(stream)` – update the fee and off-peg multiplier.

These operations emit `RampA`, `StopRampA` and `ApplyNewFee` events respectively.

## Math overview

Stable pools use an invariant `D` derived from Curve's formula that blends constant sum and constant product behavior. Key helpers include:

* `get_D(xp, amp)` – iteratively solves for the invariant given normalized balances `xp` and amplification factor `amp`.
* `get_y(i, j, x, xp, amp, d)` – given a new balance `x` for coin `i`, computes the resulting balance of coin `j` while keeping `D` constant.
* `amp()` – returns the current amplification coefficient, linearly interpolating during a ramp.
* `internal_dynamic_fee(xpi, xpj, fee)` – increases the fee when trading pushes the pool away from the peg.

These functions ensure swaps and liquidity changes respect the invariant while allowing very efficient trades around the equilibrium price.

## Utility functions

The module exposes several read‑only helpers:

* `n_coins`, `rate_multipliers`, `stored_balances`
* `initial_a`, `future_a`, `initial_a_time`, `future_a_time`
* `fee_rate` and `fee_denominator`
* `total_shares`, `get_position` and `position_shares`
* `get_dx` / `get_dy` to preview swap amounts

## Events

Stable swap pools emit rich events for indexers:

* `PoolCreated`
* `LiquidityAdded`
* `LiquidityRemoved`, `LiquidityOneRemoved`, `LiquidityImbalanceRemoved`
* `Swapped`
* `RampA` and `StopRampA`
* `ApplyNewFee`

## Security considerations

The code asserts valid fee tiers, checks invariant calculations, prevents position underflow and enforces ramping constraints. These safeguards help maintain pool integrity and protect LPs.

***

Stable swap pools complement Tapp's AMM and CLMM offerings by enabling efficient trading between pegged assets. Understanding the Move implementation allows integrators to estimate pricing, manage liquidity and monitor the health of each pool.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tapp-exchange.gitbook.io/tapp-exchange/developer-docs/stable-swap.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
