# Smart Contract

## Smart Contract

We use a **BCS (Binary Canonical Serialization)** stream to interact with **V2**, **V3**, and **Stable** pool hooks on Aptos. This documentation provides an overview of the serialization and transaction building process using the Aptos SDK in JavaScript/TypeScript.

## 📚 Table of Contents

* [Smart Contract Address](#smart-contract-addresses)
* [Interaction](#interaction)
* [Create Pool](#create-pool)
  * [AMM](#amm)
  * [CLMM](#clmm)
  * [Stable](#stable)
* [Add Liquidity](#add-liquidity)
  * [AMM](#amm-1)
  * [CLMM](#clmm-1)
  * [Stable](#stable-1)
* [Create Pool And Add Liquidity](#create-pool-and-add-liquidity)
  * [AMM](#amm-2)
  * [CLMM](#clmm-2)
  * [Stable](#stable-2)
* [Swap](#swap)
  * [AMM](#amm-3)
  * [CLMM](#clmm-3)
  * [Stable](#stable-3)
* [Remove Liquidity](#remove-liquidity)
  * [AMM](#amm-4)
  * [CLMM](#clmm-4)
  * [Stable](#stable-4)
* [Remove Multi Liquidity](#remove-multi-liquidity)
  * [AMM](#amm-5)
  * [CLMM](#clmm-5)
  * [Stable](#stable-5)
* [Collect Fee](#collect-fee)
  * [CLMM](#clmm-6)
* [Gauge Commit / Uncommit](#gauge-commit--uncommit)
* [Submitting the Transaction](#-submitting-the-transaction)
* [View](#view)
  * [Example Usage](#example-usage)
  * [AMM View API](#amm-view-api)
    * [Reserves & Shares](#-reserves--shares)
    * [Positions](#-positions)
    * [Fees](#-fees)
    * [Liquidity Calculations](#-liquidity-calculations)
    * [Swap Calculations](#-swap-calculations)
  * [CLMM View API](#clmm-view-api)
    * [Pool-Level Views](#pool-level-views)
    * [Position-Level Views](#position-level-views)
    * [Fee Views](#fee-views)
    * [Swap Simulation](#swap-simulation)
    * [Liquidity Calculations](#liquidity-calculations)
  * [Stable View API](#stable-view-api)
* [TAPP View API](#tapp-view-api)
* [veTAPP Smart Contract](#vetapp-smart-contract)
  * [veTAPP Contract Addresses](#vetapp-contract-addresses)
  * [Gauge Operations](#gauge-operations)
    * [`fees_voting_reward::earned`](#fees_voting_rewardearned)
    * [`bribe_voting_reward::earned`](#bribe_voting_rewardearned)
    * [`claim_fees`](#claim_fees)
    * [`claim_bribes`](#claim_bribes)
  * [Lock](#lock)
    * [`create_lock`](#create_lock)
    * [`withdraw`](#withdraw)
    * [`increase_amount`](#increase_amount)
    * [`increase_unlock_time`](#increase_unlock_time)
    * [`merge`](#merge)
    * [`split`](#split)
    * [`create_perm_lock`](#create_perm_lock)
    * [`create_lock_for`](#create_lock_for)
    * [`create_perm_lock_for`](#create_perm_lock_for)
    * [`deposit_for`](#deposit_for)
    * [`lock_permanent`](#lock_permanent)
    * [`unlock_permanent`](#unlock_permanent)
* [Fee Guide](#-fee-guide)

***

## Smart Contract Addresses

Use the following addresses to interact with the smart contract:

| Kind               | Address                                                              |
| ------------------ | -------------------------------------------------------------------- |
| **View Address**   | `0xf5840b576a3a6a42464814bc32ae1160c50456fb885c62be389b817e75b2a385` |
| **Router Address** | `0x487e905f899ccb6d46fdaec56ba1e0c4cf119862a16c409904b8c78fab1f5e8a` |

Use this value when referencing `routerAddress` in your transactions and `viewAddress` in your view.

***

## Interaction

Before interacting with the smart contracts, you must:

* Import required classes such as `Serializer` and `AccountAddress` from the Aptos SDK.
* Initialize a serializer instance before sending any transaction data.
* The transaction examples below are for position v1. Position v2 is an internal flow and is not documented here.

```ts
// Serializer setup
const ser = new Serializer();
```

***

### Create Pool

Function

```ts
router::create_pool
```

#### AMM

#### 📝 Parameters

| Name     | Type              | Description                      | Serialization                                                                                |
| -------- | ----------------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
| poolType | `u8`              | Pool type (2 = V2)               | `ser.serializeU8(2);`                                                                        |
| assets   | `vector<address>` | List of coin types (2 addresses) | `ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);` |
| fee      | `u64`             | Fee in basis points (bps)        | <p><code>ser.serializeU64(fee);</code><br>e.g. <code>3000</code> = 0.3%</p>                  |

#### 💡 Example

```ts
ser.serializeU8(2); // V2

ser.serializeVector([
    AccountAddress.fromString(coinA),
    AccountAddress.fromString(coinB),
]);

ser.serializeU64(3000); // Fee = 0.3%
```

***

#### CLMM

#### 📝 Parameters

| Name      | Type              | Description                             | Serialization                                                                                |
| --------- | ----------------- | --------------------------------------- | -------------------------------------------------------------------------------------------- |
| poolType  | `u8`              | Pool type (3 = V3)                      | `ser.serializeU8(3);`                                                                        |
| assets    | `vector<address>` | List of coin types (2 addresses)        | `ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);` |
| fee       | `u64`             | Fee in basis points (bps)               | <p><code>ser.serializeU64(fee);</code><br>e.g. <code>3000</code> = 0.3%</p>                  |
| sqrtPrice | `u128`            | Initial square root price for the pool. | `ser.serializeU128(sqrtPrice);`                                                              |

#### 💡 Example

```ts
ser.serializeU8(3); // V3

ser.serializeVector([
    AccountAddress.fromString(coinA),
    AccountAddress.fromString(coinB),
]);

ser.serializeU64(3000); // Fee = 0.3%

// initial square root price.
ser.serializeU128(sqrtPrice);
```

***

#### Stable

#### 📝 Parameters

| Name             | Type              | Description                                               | Serialization                                                                                |
| ---------------- | ----------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| poolType         | `u8`              | Pool type (4 = Stable)                                    | `ser.serializeU8(4);`                                                                        |
| assets           | `vector<address>` | List of coin types (max 4 addresses)                      | `ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);` |
| fee              | `u64`             | Fee in basis points (bps)                                 | <p><code>ser.serializeU64(fee);</code><br>e.g. <code>3000</code> = 0.3%</p>                  |
| amp              | `u256`            | Amplification factor. Value must be between 100 and 1000. | `ser.serializeU256(amp);`                                                                    |
| offPegMultiplier | `u256`            | off peg multiplier.                                       | `ser.serializeU256(offpeg_fee_multiplier);`                                                  |

#### 💡 Example

```ts
// pool type
ser.serializeU8(4);

// assets, support up to 4 coins.
ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);

// fee 1_000_000 for 0.01%, and 5_000_000 for 0.05%
ser.serializeU64(fee);

// amp. Between 100 to max 1000
ser.serializeU256(amp);

// off peg multiplier
ser.serializeU256(offpeg_fee_multiplier);

```

***

### Add Liquidity

Function

```ts
router::add_liquidity
```

#### AMM

#### 📝 Parameters

| Name         | Type                           | Description                                          | Serialization                                                                             |
| ------------ | ------------------------------ | ---------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| poolId       | `address`                      | Address of the pool                                  | `ser.serialize(AccountAddress.fromString(poolId));`                                       |
| positionAddr | `address` or `Option<address>` | Address of existing position or `None` to create new | `AccountAddress.fromString(positionAddr).serialize(ser);` or `ser.serializeOption(null);` |
| amountA      | `u64`                          | Desired amount of token A                            | `ser.serializeU64(amountA);`                                                              |
| amountB      | `u64`                          | Desired amount of token B                            | `ser.serializeU64(amountB);`                                                              |
| minAmountA   | `u64`                          | Minimum amount of token A (slippage protection)      | `ser.serializeU64(0);`                                                                    |
| minAmountB   | `u64`                          | Minimum amount of token B (slippage protection)      | `ser.serializeU64(0);`                                                                    |

#### 💡 Example

```ts
ser.serialize(AccountAddress.fromString(poolId));

// If creating new position, use:
// ser.serializeOption(null);
AccountAddress.fromString(positionAddr).serialize(ser);

ser.serializeU64(amountA);
ser.serializeU64(amountB);

// Slippage protection set to zero
ser.serializeU64(0);
ser.serializeU64(0);
```

***

#### CLMM

#### 📝 Parameters

| Name         | Type                           | Description                                          | Serialization                                                                             |
| ------------ | ------------------------------ | ---------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| poolId       | `address`                      | Address of the pool                                  | `ser.serialize(AccountAddress.fromString(poolId));`                                       |
| positionAddr | `address` or `Option<address>` | Address of existing position or `None` to create new | `AccountAddress.fromString(positionAddr).serialize(ser);` or `ser.serializeOption(null);` |
| amountA      | `u64`                          | Desired amount of token A                            | `ser.serializeU64(amountA);`                                                              |
| amountB      | `u64`                          | Desired amount of token B                            | `ser.serializeU64(amountB);`                                                              |
| fixedAmountA | `bool`                         | if true then its expect amountA to be fixed.         | `ser.serializeBool(fixed_amount_a);`                                                      |
| lowerTick    | `u64`                          | Lower Tick                                           | `ser.serializeU64(lower_tick);`                                                           |
| upperTick    | `u64`                          | Upper Tick                                           | `ser.serializeU64(upper_tick);`                                                           |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));

// position address. Use ser.serializeOption(null) if the user wants to create a new position.
AccountAddress.fromString(positionAddr).serialize(ser);

// The desired amount of the first token to be added
ser.serializeU64(amountA);

// The desired amount of the second token to be added
ser.serializeU64(amountB);

// fixed_amount_a true if we expect amount_a to be fixed.
ser.serializeBool(fixed_amount_a);

// lower_tick
ser.serializeU64(lower_tick);

// upper_tick
ser.serializeU64(upper_tick);

```

***

#### Stable

#### 📝 Parameters

| Name          | Type                           | Description                                          | Serialization                                                                             |
| ------------- | ------------------------------ | ---------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| poolId        | `address`                      | Address of the pool                                  | `ser.serialize(AccountAddress.fromString(poolId));`                                       |
| positionAddr  | `address` or `Option<address>` | Address of existing position or `None` to create new | `AccountAddress.fromString(positionAddr).serialize(ser);` or `ser.serializeOption(null);` |
| amounts       | `vector<u256>`                 | desired amounts for each coin with maximum 4 coins.  | `ser.serializeVector(amounts.map(amount => new U256(amount)));`                           |
| minMintAmount | `u256`                         | The minimum LP amount                                | `ser.serializeU256(min_mint_amount);`                                                     |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));

// position address. Use ser.serializeOption(null) if the user wants to create a new position.
AccountAddress.fromString(positionAddr).serialize(ser);

// The desired amount for each coin.
ser.serializeVector(amounts.map(amount => new U256(amount)));

// The minimum LP amount
ser.serializeU256(min_mint_amount);


```

***

### Create Pool And Add Liquidity

Function

```ts
router::create_pool_add_liquidity
```

#### AMM

#### 📝 Parameters

| Name         | Type                           | Description                                          | Serialization                                                                                |
| ------------ | ------------------------------ | ---------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| poolType     | `u8`                           | Pool type (2 = V2)                                   | `ser.serializeU8(2);`                                                                        |
| assets       | `vector<address>`              | List of coin address (2 addresses)                   | `ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);` |
| fee          | `u64`                          | Fee in basis points (bps)                            | <p><code>ser.serializeU64(fee);</code><br>e.g. <code>3000</code> = 0.3%</p>                  |
| positionAddr | `address` or `Option<address>` | Address of existing position or `None` to create new | `AccountAddress.fromString(positionAddr).serialize(ser);` or `ser.serializeOption(null);`    |
| amountA      | `u64`                          | Desired amount of token A                            | `ser.serializeU64(amountA);`                                                                 |
| amountB      | `u64`                          | Desired amount of token B                            | `ser.serializeU64(amountB);`                                                                 |
| minAmountA   | `u64`                          | Minimum amount of token A (slippage protection)      | `ser.serializeU64(0);`                                                                       |
| minAmountB   | `u64`                          | Minimum amount of token B (slippage protection)      | `ser.serializeU64(0);`                                                                       |

#### 💡 Example

```ts
// pool type
ser.serializeU8(2);

// assets
ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);

// fee. 100 for 0.01%, 500 for 0.05%, 3000 for 0.3%, 10000 for 1%.
ser.serializeU64(fee);

// position address. Use ser.serializeOption() if the user wants to create a new position.
AccountAddress.fromString(positionAddr).serialize(ser);

// The desired amount of the first token to be added
ser.serializeU64(amountA);

// The desired amount of the second token to be added
ser.serializeU64(amountB);

// The minimum amount of the first token that must be added
ser.serializeU64(0);

// The minimum amount of the second token that must be added
ser.serializeU64(0);

```

***

#### CLMM

#### 📝 Parameters

| Name         | Type              | Description                                  | Serialization                                                                                |
| ------------ | ----------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------- |
| poolType     | `u8`              | Pool type (3 = V3)                           | `ser.serializeU8(3);`                                                                        |
| assets       | `vector<address>` | List of coin address (2 addresses)           | `ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);` |
| fee          | `u64`             | Fee in basis points (bps)                    | <p><code>ser.serializeU64(fee);</code><br>e.g. <code>3000</code> = 0.3%</p>                  |
| sqrtPrice    | `u128`            | Initial square root price for the pool.      | `ser.serializeU128(sqrtPrice);`                                                              |
| amountA      | `u64`             | Desired amount of token A                    | `ser.serializeU64(amountA);`                                                                 |
| amountB      | `u64`             | Desired amount of token B                    | `ser.serializeU64(amountB);`                                                                 |
| fixedAmountA | `bool`            | if true then its expect amountA to be fixed. | `ser.serializeBool(fixed_amount_a);`                                                         |
| lowerTick    | `u64`             | Lower Tick                                   | `ser.serializeU64(lower_tick);`                                                              |
| upperTick    | `u64`             | Upper Tick                                   | `ser.serializeU64(upper_tick);`                                                              |

#### 💡 Example

```ts
// pool type
ser.serializeU8(3);

// assets
ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);

// fee. 100 for 0.01%, 500 for 0.05%, 3000 for 0.3%, 10000 for 1%.
ser.serializeU64(fee);

// initial square root price.
ser.serializeU128(sqrtPrice);

// The desired amount of the first token to be added
ser.serializeU64(amountA);

// The desired amount of the second token to be added
ser.serializeU64(amountB);

// fixed_amount_a true if we expect amount_a to be fixed.
ser.serializeBool(fixed_amount_a);

// lower_tick
ser.serializeU64(lower_tick);

// upper_tick
ser.serializeU64(upper_tick);
```

***

#### Stable

#### 📝 Parameters

| Name             | Type              | Description                                               | Serialization                                                                                |
| ---------------- | ----------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| poolType         | `u8`              | Pool type (4 = Stable)                                    | `ser.serializeU8(4);`                                                                        |
| assets           | `vector<address>` | List of coin address (max 4 addresses)                    | `ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);` |
| fee              | `u64`             | Fee in basis points (bps)                                 | <p><code>ser.serializeU64(fee);</code><br>e.g. <code>3000</code> = 0.3%</p>                  |
| amp              | `u256`            | Amplification factor. Value must be between 100 and 1000. | `ser.serializeU256(amp);`                                                                    |
| offPegMultiplier | `u256`            | off peg multiplier.                                       | `ser.serializeU256(offpeg_fee_multiplier);`                                                  |
| amounts          | `vector<u256>`    | desired amounts for each coin with maximum 4 coins.       | `ser.serializeVector(amounts.map(amount => new U256(amount)));`                              |
| minMintAmount    | `u256`            | The minimum LP amount                                     | `ser.serializeU256(min_mint_amount);`                                                        |

#### 💡 Example

```ts
// pool type
ser.serializeU8(4);

// assets, support up to 4 coins.
ser.serializeVector([AccountAddress.fromString(coinA), AccountAddress.fromString(coinB)]);

// fee 1_000_000 for 0.01%, and 5_000_000 for 0.05%
ser.serializeU64(fee);

// amp. Between 100 to max 1000
ser.serializeU256(amp);

// off peg multiplier
ser.serializeU256(offpeg_fee_multiplier);

// Initial liquidity for each coins
ser.serializeVector(amounts.map(amount => new U256(amount)));

// minimum LP mint amount
ser.serializeU256(min_mint_amount);
```

***

### Swap

Function

```ts
router::swap
```

#### AMM

#### 📝 Parameters

| Name          | Type      | Description                                                           | Serialization                                       |
| ------------- | --------- | --------------------------------------------------------------------- | --------------------------------------------------- |
| poolId        | `address` | Address of the pool                                                   | `ser.serialize(AccountAddress.fromString(poolId));` |
| aToB          | `bool`    | Set to true when swapping from token0 to token1 in the pool.          | `ser.serializeBool(aToB);`                          |
| fixedAmountIn | `bool`    | Indicates whether the input amount will remain fixed during the swap. | `ser.serializeBool(fixed_amount_in);`               |
| amountIn      | `u64`     | Quantity of input tokens to swap                                      | `ser.serializeU64(amountIn);`                       |
| amountOutMin  | `u64`     | Minimum quantity of output tokens expected from the swap,             | `ser.serializeU64(amountOutMin);`                   |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));

// swap from tokenA to tokenB
ser.serializeBool(aToB);

// fixed_amount_in.
// True = swap_exact_tokens_for_tokens
// False = swap_tokens_for_exact_tokens
ser.serializeBool(fixed_amount_in);


// amount in
ser.serializeU64(amountIn);

// minimum amount out
ser.serializeU64(amountOutMin);
```

***

#### CLMM

#### 📝 Parameters

| Name            | Type      | Description                                                           | Serialization                                       |
| --------------- | --------- | --------------------------------------------------------------------- | --------------------------------------------------- |
| poolId          | `address` | Address of the pool                                                   | `ser.serialize(AccountAddress.fromString(poolId));` |
| aToB            | `bool`    | Set to true when swapping from token0 to token1 in the pool.          | `ser.serializeBool(aToB);`                          |
| fixedAmountIn   | `bool`    | Indicates whether the input amount will remain fixed during the swap. | `ser.serializeBool(fixed_amount_in);`               |
| amountIn        | `u64`     | Quantity of input tokens to swap                                      | `ser.serializeU64(amountIn);`                       |
| amountOutMin    | `u64`     | Minimum quantity of output tokens expected from the swap,             | `ser.serializeU64(amountOutMin);`                   |
| targetSqrtPrice | `u128`    | target square root price after swap.                                  | `ser.serializeU128(target_sqrt_price);`             |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));

// swap from tokenA to tokenB
ser.serializeBool(aToB);

// fixed_amount_in.
ser.serializeBool(fixed_amount_in);

// amount in.
ser.serializeU64(amountIn);

// minimum amount out.
ser.serializeU64(amountOutMin);

// target square root price after swap.
ser.serializeU128(target_sqrt_price);

```

***

#### Stable

#### 📝 Parameters

| Name         | Type      | Description         | Serialization                                       |
| ------------ | --------- | ------------------- | --------------------------------------------------- |
| poolId       | `address` | Address of the pool | `ser.serialize(AccountAddress.fromString(poolId));` |
| tokenIn      | `u64`     | token index in.     | `ser.serializeU64(tokenIn);`                        |
| tokenOut     | `u64`     | token index out.    | `ser.serializeU64(tokenOut);`                       |
| amountIn     | `u256`    | amount in.          | `ser.serializeU256(amountIn);`                      |
| minAmountOut | `u256`    | min amount out,     | `ser.serializeU256(min_amount_out);`                |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));

// i. token index in
ser.serializeU64(tokenIn);

// j. token index out
ser.serializeU64(tokenOut);

// dx. amount in
ser.serializeU256(amountIn);

// min_dy. min amount out
ser.serializeU256(min_amount_out);
```

### Remove Liquidity

Function

```ts
router::remove_liquidity
```

#### AMM

#### 📝 Parameters

| Name         | Type      | Description                                                                     | Serialization                                             |
| ------------ | --------- | ------------------------------------------------------------------------------- | --------------------------------------------------------- |
| poolId       | `address` | Address of the pool                                                             | `ser.serialize(AccountAddress.fromString(poolId));`       |
| positionAddr | `address` | Address of existing position                                                    | `ser.serialize(AccountAddress.fromString(positionAddr));` |
| burnedShares | `u128`    | Amount of liquidity provider (LP) tokens or shares to burn/remove from the pool | `ser.serializeU128(burnedShares);`                        |
| minAmountA   | `u64`     | Minimum token A amounts to receive when removing liquidity.                     | `ser.serializeU64(minAmountA);`                           |
| minAmountB   | `u64`     | Minimum token B amounts to receive when removing liquidity.                     | `ser.serializeU64(minAmountB);`                           |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));

// position address
ser.serialize(AccountAddress.fromString(positionAddr));

// burned share
ser.serializeU128(burnedShares);

// min_amount_a
ser.serializeU64(minAmountA);

// min_amount_b
ser.serializeU64(minAmountB);
```

***

#### CLMM

#### 📝 Parameters

| Name         | Type      | Description                                                                     | Serialization                                             |
| ------------ | --------- | ------------------------------------------------------------------------------- | --------------------------------------------------------- |
| poolId       | `address` | Address of the pool                                                             | `ser.serialize(AccountAddress.fromString(poolId));`       |
| positionAddr | `address` | Address of existing position                                                    | `ser.serialize(AccountAddress.fromString(positionAddr));` |
| burnedShares | `u128`    | Amount of liquidity provider (LP) tokens or shares to burn/remove from the pool | `ser.serializeU128(burnedShares);`                        |
| minAmountA   | `u64`     | Minimum token A amounts to receive when removing liquidity.                     | `ser.serializeU64(minAmountA);`                           |
| minAmountB   | `u64`     | Minimum token B amounts to receive when removing liquidity.                     | `ser.serializeU64(minAmountB);`                           |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));

// position address
ser.serialize(AccountAddress.fromString(positionAddr));

// burned share
ser.serializeU128(burnedShares);

// min_amount_a
ser.serializeU64(minAmountA);

// min_amount_b
ser.serializeU64(minAmountB);
```

***

#### Stable

#### 📝 Parameters

| Name         | Type           | Description                                                                               | Serialization                                                   |
| ------------ | -------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| poolId       | `address`      | Address of the pool                                                                       | `ser.serialize(AccountAddress.fromString(poolId));`             |
| positionAddr | `address`      | Address of existing position                                                              | `ser.serialize(AccountAddress.fromString(positionAddr));`       |
| Type         | `u8`           | 1 : remove liquidity one coin, 2 : remove liquidity imbalance, 3 : remove liquidity ratio | `ser.serializeU8(3)`                                            |
| burnedShare  | `u256`         | Amount of liquidity provider (LP) tokens or shares to burn/remove from the pool           | `ser.serializeU256(shares);`                                    |
| minAmounts   | `vector<u256>` | Minimum token amounts to receive when removing liquidity.                                 | `ser.serializeVector(amounts.map(amount => new U256(amount)));` |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));

// position address
ser.serialize(AccountAddress.fromString(positionAddr));

// type 1 = remove_liquidity_one_coin
// type 2 =remove_liquidity_imbalance
// type 3 = remove_liquidity_ratio
ser.serializeU8(3)

// burn amount
ser.serializeU256(shares);

// minimum received for each token
ser.serializeVector(amounts.map(amount => new U256(amount)));
```

***

### Remove Multi Liquidity

Function

```ts
router::remove_multi_liquidity
```

#### AMM

#### 📝 Parameters

| Name                      | Type      | Description                                                                     | Serialization                                                      |
| ------------------------- | --------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| poolId                    | `address` | Address of the pool                                                             | `ser.serialize(AccountAddress.fromString(poolId));`                |
| positions.length          | `u64`     | Total number of positions                                                       | `ser.serializeU64(positions.length);`                              |
| positions.positionAddress | `address` | Address of existing position                                                    | `ser.serialize(AccountAddress.fromString(position.positionAddr));` |
| positions.burnedShares    | `u128`    | Amount of liquidity provider (LP) tokens or shares to burn/remove from the pool | `ser.serializeU128(position.burnedShares);`                        |
| positions.minAmountA      | `u64`     | Minimum token A amounts to receive when removing liquidity.                     | `ser.serializeU64(position.minAmountA);`                           |
| positions.minAmountB      | `u64`     | Minimum token B amounts to receive when removing liquidity.                     | `ser.serializeU64(position.minAmountB);`                           |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));
// number of positions
ser.serializeU64(positions.length);

positions.forEach((position) => {
    // position address
    ser.serialize(AccountAddress.fromString(position.positionAddr));

    // burned_shares
    ser.serializeU128(position.burnedShares);

    // min_amount_a
    ser.serializeU64(position.minAmountA);

    // min_amount_b
    ser.serializeU64(position.minAmountB);
})
```

***

#### CLMM

#### 📝 Parameters

| Name                      | Type      | Description                                                                     | Serialization                                                      |
| ------------------------- | --------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| poolId                    | `address` | Address of the pool                                                             | `ser.serialize(AccountAddress.fromString(poolId));`                |
| positions.length          | `u64`     | Total number of positions                                                       | `ser.serializeU64(positions.length);`                              |
| positions.positionAddress | `address` | Address of existing position                                                    | `ser.serialize(AccountAddress.fromString(position.positionAddr));` |
| positions.burnedShares    | `u128`    | Amount of liquidity provider (LP) tokens or shares to burn/remove from the pool | `ser.serializeU128(position.burnedShares);`                        |
| positions.minAmountA      | `u64`     | Minimum token A amounts to receive when removing liquidity.                     | `ser.serializeU64(position.minAmountA);`                           |
| positions.minAmountB      | `u64`     | Minimum token B amounts to receive when removing liquidity.                     | `ser.serializeU64(position.minAmountB);`                           |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));
// number of positions
ser.serializeU64(positions.length);

positions.forEach((position) => {
    // position address
    ser.serialize(AccountAddress.fromString(position.positionAddr));

    // burned_shares
    ser.serializeU128(position.burnedShares);

    // min_amount_a
    ser.serializeU64(position.minAmountA);

    // min_amount_b
    ser.serializeU64(position.minAmountB);
})
```

***

#### Stable

#### 📝 Parameters

| Name                   | Type           | Description                                                                               | Serialization                                                               |
| ---------------------- | -------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| poolId                 | `address`      | Address of the pool                                                                       | `ser.serialize(AccountAddress.fromString(poolId));`                         |
| positions.length       | `u64`          | Total number of positions                                                                 | `ser.serializeU64(positions.length);`                                       |
| positions.positionAddr | `address`      | Address of existing position                                                              | `ser.serialize(AccountAddress.fromString(position.positionAddr))`           |
| positions.type         | `u8`           | 1 : remove liquidity one coin, 2 : remove liquidity imbalance, 3 : remove liquidity ratio | `ser.serializeU8(position.type);`                                           |
| positions.burnedShare  | `u256`         | Amount of liquidity provider (LP) tokens or shares to burn/remove from the pool           | `ser.serializeU128(position.burnedShare);`                                  |
| positions.minAmounts   | `vector<u256>` | Minimum token amounts to receive when removing liquidity.                                 | `ser.serializeVector(position.minAmounts.map(amount => new U256(amount)));` |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));
// number of positions
ser.serializeU64(positions.length);

positions.forEach(position => {
    // position address
    ser.serialize(AccountAddress.fromString(position.positionAddr));

    // type 1 = remove_liquidity_one_coin
    // type 2 =remove_liquidity_imbalance
    // type 3 = remove_liquidity_ratio
    ser.serializeU8(position.type);

    // burned_shares
    ser.serializeU256(position.burnedShare);

    // minimum received for each token
    ser.serializeVector(position.minAmounts.map(amount => new U256(amount)));
})

```

***

### Collect Fee

Function

```ts
router::collect_fee
```

#### CLMM

#### 📝 Parameters

| Name            | Type      | Description                  | Serialization                                                |
| --------------- | --------- | ---------------------------- | ------------------------------------------------------------ |
| poolId          | `address` | Address of the pool          | `ser.serialize(AccountAddress.fromString(poolId));`          |
| positionAddress | `address` | Address of existing position | `AccountAddress.fromString(positionAddress).serialize(ser);` |

#### 💡 Example

```ts
// pool id
ser.serialize(AccountAddress.fromString(poolId));

// position address
AccountAddress.fromString(positionAddress).serialize(ser);
```

### Gauge Commit / Uncommit

These are direct entry functions in `tapp::ve`, not BCS-packed router payloads. `gauge_commit` claims any owed fees before committing the position, and `gauge_uncommit` claims any owed gauge rewards before releasing it.

#### Gauge Commit

Function

```ts
tapp::ve::gauge_commit
```

#### 📝 Parameters

| Name         | Type          | Description                                                         |
| ------------ | ------------- | ------------------------------------------------------------------- |
| poolAddr     | `address`     | Address of the pool                                                 |
| positionAddr | `address`     | Address of the position to commit                                   |
| positionIdx  | `Option<u64>` | Position index for position v2. Use `none()` for position v1 flows. |

#### 💡 Example

```ts
// position v1
await aptos.transaction.build.simple({
    sender: account.accountAddress,
    data: {
        function: `${tappAddress}::ve::gauge_commit`,
        functionArguments: [poolAddr, positionAddr, null],
    },
});
```

#### Gauge Uncommit

Function

```ts
tapp::ve::gauge_uncommit
```

#### 📝 Parameters

| Name         | Type          | Description                                                         |
| ------------ | ------------- | ------------------------------------------------------------------- |
| poolAddr     | `address`     | Address of the pool                                                 |
| positionAddr | `address`     | Address of the position to uncommit                                 |
| positionIdx  | `Option<u64>` | Position index for position v2. Use `none()` for position v1 flows. |

#### 💡 Example

```ts
// position v1
await aptos.transaction.build.simple({
    sender: account.accountAddress,
    data: {
        function: `${tappAddress}::ve::gauge_uncommit`,
        functionArguments: [poolAddr, positionAddr, null],
    },
});
```

### 🚀 Submitting the Transaction

Once all arguments are serialized, submit the transaction using the Aptos SDK:

```ts
const transaction = await aptos.transaction.build.simple({
    sender: account.accountAddress,
    data: {
        function: `${routerAddress}::${functionName}`,
        functionArguments: [ser.toUint8Array()],
    },
});
```

***

## View

This documentation provides read-only access to key on-chain data across multiple pool types, including pool state, user positions, and swap simulations. It is intended for developers and integrators to support analytics, UI rendering, and off-chain logic without modifying blockchain state.

### Example Usage

To interact with the View API, you can use the `views` module provided by the `aptos` framework. This module contains read-only functions that allow you to query various aspects of the AMM, CLMM, and Stable pools without modifying the on-chain state.

**Example usage in JavaScript:**

```javascript

async function getPoolReserves(poolAddress) {
    const reservesA = await aptos.view({
        function: `${viewAddress}::amm_views::reserve_a`,
        type_arguments: [],
        arguments: [poolAddress],
    });

    const reservesB = await aptos.view({
        function: `${viewAddress}::amm_views::reserve_b`,
        type_arguments: [],
        arguments: [poolAddress],
    });

    return {reservesA, reservesB};
}
```

***

### AMM View API

The `views::amm_views` module provides a collection of read-only view functions designed to interact with and retrieve information from AMM (Automated Market Maker) pools. These functions are useful for frontend queries and off-chain data display.

***

#### 📊 Reserves & Shares

**Function `reserve_a(pool_addr: address): u64`**

Returns the reserve amount of token A in the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const reservesA = await aptos.view({
    function: `${viewAddress}::amm_views::reserve_a`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `reserve_b(pool_addr: address): u64`**

Returns the reserve amount of token B in the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const reservesB = await aptos.view({
    function: `${viewAddress}::amm_views::reserve_b`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `total_shares(pool_addr: address): u128`**

Returns the total number of LP shares for the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const totalShares = await aptos.view({
    function: `${viewAddress}::amm_views::total_shares`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

#### 🧾 Positions

**Function `get_positions(pool_addr: address): vector<amm::amm::Position>`**

Returns all positions in a given pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const positions = await aptos.view({
    function: `${viewAddress}::amm_views::get_positions`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `get_position(pool_addr: address, position_idx: u64): amm::amm::Position`**

Returns the position information for a specific index.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `position_idx`: `u64` – Index of the position within the pool.

**💡 Example**

```javascript
const position = await aptos.view({
    function: `${viewAddress}::amm_views::get_position`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

**Function `position_shares(pool_addr: address, position_idx: u64): u128`**

Returns the number of shares owned by the position.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `position_idx`: `u64` – Index of the position within the pool.

**💡 Example**

```javascript
const shares = await aptos.view({
    function: `${viewAddress}::amm_views::position_shares`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

#### 💸 Fees

**Function `fee_rate(pool_addr: address): u64`**

Returns the fee rate for the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const feeRate = await aptos.view({
    function: `${viewAddress}::amm_views::fee_rate`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `fee_rate_denominator(): u64`**

Returns the denominator used to calculate the fee percentage.

**💡 Example**

```javascript
const denominator = await aptos.view({
    function: `${viewAddress}::amm_views::fee_rate_denominator`,
    type_arguments: [],
    arguments: [],
});
```

***

#### ➕ Liquidity Calculations

**Function**

`calc_optimal_lp_amount(desired_amount_a: u64, desired_amount_b: u64, min_amount_a: u64, min_amount_b: u64)`

Calculates optimal token amounts to add liquidity while maintaining ratio.

**Params**

* `desired_amount_a`: u64
* `desired_amount_b`: u64
* `min_amount_a`: u64
* `min_amount_b`: u64

**💡 Example**

```javascript
const optimalAmounts = await aptos.view({
    function: `${viewAddress}::amm_views::calc_optimal_lp_amount`,
    type_arguments: [],
    arguments: [desiredAmountA, desiredAmountB, minAmountA, minAmountB],
});
```

***

**Function `compute_lp_from_shares(pool_addr: address, shares: u128): (u64, u64)`**

Calculates the equivalent amounts of token A and B from given LP shares.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `shares`: `u128` – Number of LP shares to convert.

**💡 Example**

```javascript
const amounts = await aptos.view({
    function: `${viewAddress}::amm_views::compute_lp_from_shares`,
    type_arguments: [],
    arguments: [poolAddress, shares],
});
```

***

#### 🔁 Swap Calculations

**Function `compute_amount_out(pool_addr: address, amount_in: u64, a2b: bool): u64`**

Returns the estimated output token amount for a given input and direction.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `amount_in`: `u64` – Amount of input token.
* `a2b`: `bool` – Direction of swap (`true`: A to B, `false`: B to A).

**💡 Example**

```javascript
const amountOut = await aptos.view({
    function: `${viewAddress}::amm_views::compute_amount_out`,
    type_arguments: [],
    arguments: [poolAddress, amountIn, true],
});
```

***

**Function `compute_amount_in(pool_addr: address, amount_out: u64, a2b: bool): u64`**

Returns the required input token amount to receive a specific output.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `amount_out`: `u64` – Desired output token amount.
* `a2b`: `bool` – Direction of swap (`true`: A to B, `false`: B to A).

**💡 Example**

```javascript
const amountIn = await aptos.view({
    function: `${viewAddress}::amm_views::compute_amount_in`,
    type_arguments: [],
    arguments: [poolAddress, amountOut, true],
});
```

***

### CLMM View API

This module contains **read-only view functions** for accessing the on-chain state of CLMM (Concentrated Liquidity Market Maker) pools and positions. All methods are non-mutating and safe to call for off-chain querying.

***

#### Pool-Level Views

**Function `current_sqrt_price(pool_addr: address): u128`**

Returns the current square root price of the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const sqrtPrice = await aptos.view({
    function: `${viewAddress}::clmm_views::current_sqrt_price`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `reserve_a(pool_addr: address): u64`**

Returns the current reserve amount of token A in the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const reserveA = await aptos.view({
    function: `${viewAddress}::clmm_views::reserve_a`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `reserve_b(pool_addr: address): u64`**

Returns the current reserve amount of token B in the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const reserveB = await aptos.view({
    function: `${viewAddress}::clmm_views::reserve_b`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `liquidity(pool_addr: address): u128`**

Returns the total liquidity currently in the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const liquidity = await aptos.view({
    function: `${viewAddress}::clmm_views::liquidity`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `current_tick_idx(pool_addr: address): u64`**

Returns the current tick index for the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const tickIndex = await aptos.view({
    function: `${viewAddress}::clmm_views::current_tick_idx`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

#### Position-Level Views

**Function `get_positions(pool_addr: address): vector<clmm::clmm::Position>`**

Fetches all position objects within the specified pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const positions = await aptos.view({
    function: `${viewAddress}::clmm_views::get_positions`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `get_position(pool_addr: address, position_idx: u64): clmm::clmm::Position`**

Fetches a specific position by index from the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `position_idx`: `u64` – Index of the position within the pool.

**💡 Example**

```javascript
const position = await aptos.view({
    function: `${viewAddress}::clmm_views::get_position`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

**Function `position_liquidity(pool_addr: address, position_idx: u64): u128`**

Returns the amount of liquidity in a specific position.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `position_idx`: `u64` – Position index.

**💡 Example**

```javascript
const liquidity = await aptos.view({
    function: `${viewAddress}::clmm_views::position_liquidity`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

**Function `position_tick_idxs(pool_addr: address, position_idx: u64): (u64, u64)`**

Returns the tick lower and upper indices for a position.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `position_idx`: `u64` – Position index.

**💡 Example**

```javascript
const tickIdxs = await aptos.view({
    function: `${viewAddress}::clmm_views::position_tick_idxs`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

**Function `position_fee_growth_inside(pool_addr: address, position_idx: u64): (u128, u128)`**

Returns the fee growth inside the tick range of a position.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `position_idx`: `u64` – Position index.

**💡 Example**

```javascript
const feeGrowth = await aptos.view({
    function: `${viewAddress}::clmm_views::position_fee_growth_inside`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

**Function `position_fee_owed(pool_addr: address, position_idx: u64): (u64, u64)`**

Returns the amount of fees owed to a position.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `position_idx`: `u64` – Position index.

**💡 Example**

```javascript
const feesOwed = await aptos.view({
    function: `${viewAddress}::clmm_views::position_fee_owed`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

#### Fee Views

**Function `fee_rate(pool_addr: address): u64`**

Returns the fee rate of the pool.

**Params**

* `pool_addr`: `address` – Pool unique identifier.

**💡 Example**

```javascript
const feeRate = await aptos.view({
    function: `${viewAddress}::clmm_views::fee_rate`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `fee_denominator(): u64`**

Returns the fixed denominator used in fee calculation.

**💡 Example**

```javascript
const denominator = await aptos.view({
    function: `${viewAddress}::clmm_views::fee_denominator`,
    type_arguments: [],
    arguments: [],
});
```

***

#### Swap Simulation

**Function**

`calculate_swap_result(pool_addr: address, a2b: bool, fixed_amount_in: bool, amount: u64): clmm::clmm::CalculatedSwapResult`

Simulates a swap and returns the expected result.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `a2b`: `bool` – Direction of the swap (`true`: A to B, `false`: B to A).
* `fixed_amount_in`: `bool` – Whether the input amount is fixed.
* `amount`: `u64` – The amount to swap.

**💡 Example**

```javascript
const swapResult = await aptos.view({
    function: `${viewAddress}::clmm_views::calculate_swap_result`,
    type_arguments: [],
    arguments: [poolAddress, true, true, amount],
});
```

***

#### Liquidity Calculations

**Function `get_amount_by_liquidity(...): (u64, u64)`**

Returns the token amounts (A, B) corresponding to a given liquidity amount.

**Params**

* `tick_lower_index`: `u64` – Lower bound of tick range.
* `tick_upper_index`: `u64` – Upper bound of tick range.
* `current_tick_index`: `u64` – Current tick index.
* `current_sqrt_price`: `u128` – Current square root price.
* `liquidity`: `u128` – Amount of liquidity.
* `round_up`: `bool` – Whether to round up in calculation.

**💡 Example**

```javascript
const amounts = await aptos.view({
    function: `${viewAddress}::clmm_views::get_amount_by_liquidity`,
    type_arguments: [],
    arguments: [tickLowerIndex, tickUpperIndex, currentTickIndex, currentSqrtPrice, liquidity, true],
});
```

***

**Function**

`get_amount_by_liquidity_of(pool_addr: address, position_idx: u64, liquidity: u128, round_up: bool): (u64, u64)`

Returns the token amounts (A, B) corresponding to a given liquidity amount in a specific position.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `position_idx`: `u64` – Index of the position.
* `liquidity`: `u128` – Amount of liquidity.
* `round_up`: `bool` – Whether to round up in calculation.

**💡 Example**

```javascript
const amounts = await aptos.view({
    function: `${viewAddress}::clmm_views::get_amount_by_liquidity_of`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex, liquidity, true],
});
```

***

**Function `get_liquidity_by_amount(...): (u128, u64, u64)`**

Returns the liquidity and actual token amounts (A, B) that can be provided with a given token amount.

**Params**

* `tick_lower_index`: `u64` – Lower tick index.
* `tick_upper_index`: `u64` – Upper tick index.
* `current_tick_index`: `u64` – Current tick index.
* `current_sqrt_price`: `u128` – Current square root price.
* `amount`: `u64` – The fixed token amount.
* `is_fixed_a`: `bool` – Whether the fixed amount is token A.

**💡 Example**

```javascript
const liquidity = await aptos.view({
    function: `${viewAddress}::clmm_views::get_liquidity_by_amount`,
    type_arguments: [],
    arguments: [tickLowerIndex, tickUpperIndex, currentTickIndex, currentSqrtPrice, amount, true],
});
```

***

**Function**

`get_liquidity_by_amount_of(pool_addr: address, tick_lower_index: u64, tick_upper_index: u64, amount: u64, is_fixed_a: bool): (u128, u64, u64)`

Returns the liquidity and actual token amounts (A, B) that can be provided with a given token amount in a specific position.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `tick_lower_index`: `u64` – Lower tick index.
* `tick_upper_index`: `u64` – Upper tick index.
* `amount`: `u64` – The fixed token amount.
* `is_fixed_a`: `bool` – Whether the fixed amount is token A.

**💡 Example**

```javascript
const liquidity = await aptos.view({
    function: `${viewAddress}::clmm_views::get_liquidity_by_amount_of`,
    type_arguments: [],
    arguments: [poolAddress, tickLowerIndex, tickUpperIndex, amount, true],
});
```

***

**Function `get_position_fee_owned(pool_addr: address, position_idx: u64): (u128, u64, u64)`**

Returns the total fees owed to a position, including fee growth and amounts.

**Params**

* `pool_addr`: `address` – Pool unique identifier.
* `position_idx`: `u64` – Index of the position.

**💡 Example**

```javascript
const feesOwed = await aptos.view({
    function: `${viewAddress}::clmm_views::get_position_fee_owned`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

### Stable View API

This module provides read-only view functions for accessing on-chain data related to Stable Pools. It allows querying pool state, user positions, and swap simulations without modifying blockchain state.

***

**Function `n_coins(pool_addr: address): u64`**

returns the number of coins in the pool.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const coinCount = await aptos.view({
    function: `${viewAddress}::stable_views::n_coins`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `rate_multipliers(pool_addr: address): vector<u256>`**

returns the rate multipliers for each coin in the pool.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const rateMultipliers = await aptos.view({
    function: `${viewAddress}::stable_views::rate_multipliers`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `stored_balances(pool_addr: address): vector<u256>`**

returns the stored balances of each coin in the pool.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const balances = await aptos.view({
    function: `${viewAddress}::stable_views::stored_balances`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `initial_a(pool_addr: address): u256`**

returns the initial amplification coefficient (A) of the pool.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const initialA = await aptos.view({
    function: `${viewAddress}::stable_views::initial_a`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `future_a(pool_addr: address): u256`**

returns the future amplification coefficient (A) of the pool.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const futureA = await aptos.view({
    function: `${viewAddress}::stable_views::future_a`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `initial_a_time(pool_addr: address): u64`**

returns the timestamp when the initial amplification coefficient (A) was set.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const initialATime = await aptos.view({
    function: `${viewAddress}::stable_views::initial_a_time`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `future_a_time(pool_addr: address): u64`**

returns the timestamp when the future amplification coefficient (A) will be set.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const futureATime = await aptos.view({
    function: `${viewAddress}::stable_views::future_a_time`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `total_shares(pool_addr: address): u256`**

returns the total number of LP shares for the pool.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const totalShares = await aptos.view({
    function: `${viewAddress}::stable_views::total_shares`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `fee_rate(pool_addr: address): u256`**

returns the fee rate for the pool.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const feeRate = await aptos.view({
    function: `${viewAddress}::stable_views::fee_rate`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `fee_denominator(): u256`**

returns the denominator used to calculate the fee percentage.

**💡 Example**

```javascript
const denominator = await aptos.view({
    function: `${viewAddress}::stable_views::fee_denominator`,
    type_arguments: [],
    arguments: [],
});
```

***

**Function `dynamic_fee(pool_addr: address, i: u64, j: u64): u256`**

returns the dynamic fee rate for a specific coin pair in the pool.

**Params**

* `pool_addr`: `address` – The address of the pool.
* `i`: `u64` – The index of the first coin.
* `j`: `u64` – The index of the second coin.

**💡 Example**

```javascript
const dynamicFee = await aptos.view({
    function: `${viewAddress}::stable_views::dynamic_fee`,
    type_arguments: [],
    arguments: [poolAddress, i, j],
});
```

***

**Function `get_positions(pool_addr: address): vector<stable::stable::Position>`**

returns all positions in a given pool.

**Params**

* `pool_addr`: `address` – The address of the pool.

**💡 Example**

```javascript
const positions = await aptos.view({
    function: `${viewAddress}::stable_views::get_positions`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `get_position(pool_addr: address, position_idx: u64): stable::stable::Position`**

returns the position information for a specific index.

**Params**

* `pool_addr`: `address` – The address of the pool.
* `position_idx`: `u64` – The index of the position within the pool.

**💡 Example**

```javascript
const position = await aptos.view({
    function: `${viewAddress}::stable_views::get_position`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

**Function `position_shares(pool_addr: address, position_idx: u64): u256`**

returns the number of shares owned by the position.

**Params**

* `pool_addr`: `address` – The address of the pool.
* `position_idx`: `u64` – The index of the position within the pool.

**💡 Example**

```javascript
const shares = await aptos.view({
    function: `${viewAddress}::stable_views::position_shares`,
    type_arguments: [],
    arguments: [poolAddress, positionIndex],
});
```

***

**Function `get_dx(pool_addr: address, i: u64, j: u64, dy: u256): u256`**

this function calculates the required input amount (dx) for a given output amount (dy) in a specific coin pair.

**Params**

* `pool_addr`: `address` – The address of the pool.
* `i`: `u64` – The index of the first coin.
* `j`: `u64` – The index of the second coin.
* `dy`: `u256` – The output amount for the second coin.

**💡 Example**

```javascript
const dx = await aptos.view({
    function: `${viewAddress}::stable_views::get_dx`,
    type_arguments: [],
    arguments: [poolAddress, i, j, dy],
});
```

***

**Function `get_dy(pool_addr: address, i: u64, j: u64, dx: u256): u256`**

this function calculates the output amount (dy) for a given input amount (dx) in a specific coin pair.

**Params**

* `pool_addr`: `address` – The address of the pool.
* `i`: `u64` – The index of the first coin.
* `j`: `u64` – The index of the second coin.
* `dx`: `u256` – The input amount for the first coin.

**💡 Example**

```javascript
const dy = await aptos.view({
    function: `${viewAddress}::stable_views::get_dy`,
    type_arguments: [],
    arguments: [poolAddress, i, j, dx],
});
```

***

**Function `calc_token_amount(pool_addr: address, amounts: vector<u256>, is_deposit: bool): u256`**

this function calculates the amount of LP shares to mint or burn based on the provided token amounts.

**Params**

* `pool_addr`: `address` – The address of the pool.
* `amounts`: `vector<u256>` – The amounts of each coin to deposit or withdraw.
* `is_deposit`: `bool` – Whether the operation is a deposit (`true`) or withdrawal (`false`).

**💡 Example**

```javascript
const lpAmount = await aptos.view({
    function: `${viewAddress}::stable_views::calc_token_amount`,
    type_arguments: [],
    arguments: [poolAddress, amounts, true],
});
```

***

**Function `calc_withdraw_one_coin(pool_addr: address, burn_amount: u256, i: u64): u256`**

this function calculates the amount of a specific coin to withdraw when burning LP shares.

**Params**

* `pool_addr`: `address` – The address of the pool.
* `burn_amount`: `u256` – The amount of LP shares to burn.
* `i`: `u64` – The index of the coin to withdraw.

**💡 Example**

```javascript
const amount = await aptos.view({
    function: `${viewAddress}::stable_views::calc_withdraw_one_coin`,
    type_arguments: [],
    arguments: [poolAddress, burnAmount, i],
});
```

***

**Function `calc_ratio_amounts(pool_addr: address, liquidity: u256): vector<u256>`**

this function calculates the amounts of each coin based on a given liquidity ratio.

**Params**

* `pool_addr`: `address` – The address of the pool.
* `liquidity`: `u256` – The liquidity ratio to use for the calculation.

**💡 Example**

```javascript
const amounts = await aptos.view({
    function: `${viewAddress}::stable_views::calc_ratio_amounts`,
    type_arguments: [],
    arguments: [poolAddress, liquidity],
});
```

### TAPP View API

This documentation provides read-only access to on-chain data for TAPP protocol integrations, including pool metadata, position details, and calculated incentives. These functions help developers query reward information and render pool/position data in applications without requiring transactions.

***

**Function `get_pool_metas(): vector<tapp::hook_factory::PoolMeta>`**

Returns metadata for all TAPP pools.

**Params**

* *(no parameters)*

**💡 Example**

```javascript
const poolMetas = await aptos.view({
    function: `${viewAddress}::tapp_views::get_pool_metas`,
    type_arguments: [],
    arguments: [],
});
```

***

**Function `get_pool_meta(pool_addr: address): tapp::hook_factory::PoolMeta`**

Returns metadata for a specific TAPP pool.

**Params**

* `pool_addr`: `address` – The address of the TAPP pool.

**💡 Example**

```javascript
const poolMeta = await aptos.view({
    function: `${viewAddress}::tapp_views::get_pool_meta`,
    type_arguments: [],
    arguments: [poolAddress],
});
```

***

**Function `get_position_meta(position_addr: address): tapp::position::PositionMeta`**

Returns metadata for a specific TAPP position.

**Params**

* `position_addr`: `address` – The address of the TAPP position.

**💡 Example**

```javascript
const positionMeta = await aptos.view({
    function: `${viewAddress}::tapp_views::get_position_meta`,
    type_arguments: [],
    arguments: [positionAddress],
});
```

***

**Function**

`calc_incentives(user_address: address, pool_addr: address, position_idx: u64): vector<tapp::hook_factory::IncentiveReward>`

Calculates incentives for a specific user position in a TAPP pool.

**Params**

* `user_address`: `address` – The address of the user.
* `pool_addr`: `address` – The address of the TAPP pool.
* `position_idx`: `u64` – The index of the position within the pool.

**💡 Example**

```javascript
const incentives = await aptos.view({
    function: `${viewAddress}::tapp_views::calc_incentives`,
    type_arguments: [],
    arguments: [userAddress, poolAddress, positionIndex],
});
```

***

**Function**

`calc_incentives_batch(user_address: address, pool_addrs: vector<address>, position_indices: vector<u64>): vector<vector<tapp::hook_factory::IncentiveReward>>`

Calculates incentives for multiple user positions across multiple TAPP pools in a single call. This is more efficient than calling `calc_incentives` individually for each position.

**Params**

* `user_address`: `address` – The address of the user.
* `pool_addrs`: `vector<address>` – A vector of TAPP pool addresses.
* `position_indices`: `vector<u64>` – A vector of position indices corresponding to each pool address.

**💡 Example**

```javascript
const incentives = await aptos.view({
    function: `${viewAddress}::tapp_views::calc_incentives_batch`,
    type_arguments: [],
    arguments: [userAddress, poolAddresses, positionIndices],
});
```

***

### veTAPP Smart Contract

The `veTAPP` (Voting Escrow TAP) contract manages the locking of `TAPP` tokens into veNFTs. These NFTs represent voting power and entitle owners to rewards and governance participation.

#### veTAPP Contract Addresses

| Kind               | Address                                                              |
| ------------------ | -------------------------------------------------------------------- |
| **veTAPP Address** | `0xb0745cc707507e46f7c7510b3cbf0c782dd61530b2135e8ceba7efe39bac861f` |

***

#### Gauge Operations

These helpers belong to the veTAPP flow and interact with gauge rewards and voter emissions. The user-facing claim entrypoints live in `ve_tapp::voter` from `packages/ve_tapp/sources/protocol/voter.move`. They call into `tapp::ve`, which then forwards to the gauge package for reward accounting.

**`fees_voting_reward::earned`**

Returns the fee reward amount earned by a veTAPP NFT for a specific pool fee token.

**Parameters:**

* `pool`: `address` - Pool address.
* `ve_token_addr`: `address` - veTAPP NFT address.
* `fee_token_addr`: `address` - Fee token address.

**View Function:**

```ts
gauge::fees_voting_reward::earned(pool, ve_token_addr, fee_token_addr)
```

***

**`bribe_voting_reward::earned`**

Returns the bribe reward amount earned by a veTAPP NFT for a specific pool bribe token.

**Parameters:**

* `pool`: `address` - Pool address.
* `ve_token_addr`: `address` - veTAPP NFT address.
* `bribe_token_addr`: `address` - Bribe token address.

**View Function:**

```ts
gauge::bribe_voting_reward::earned(pool, ve_token_addr, bribe_token_addr)
```

***

**`claim_fees`**

Claims fee rewards for one or more pools on behalf of the veTAPP NFT owner.

**Parameters:**

* `caller`: `&signer` - Caller and recipient of the claimed fees.
* `pools`: `vector<address>` - Pools to claim from, in batch order.
* `tokens`: `vector<vector<address>>` - Fee token sets for each pool.
* `ve_token_addr`: `address` - ve token address used for entitlement.

**Entry Function:**

```ts
ve_tapp::voter::claim_fees(caller, pools, tokens, ve_token_addr)
```

***

**`claim_bribes`**

Claims bribe rewards for one or more pools on behalf of the veTAPP NFT owner.

**Parameters:**

* `caller`: `&signer` - Caller and recipient of the claimed bribes.
* `pools`: `vector<address>` - Pools to claim from, in batch order.
* `tokens`: `vector<vector<address>>` - Bribe token sets for each pool.
* `ve_token_addr`: `address` - ve token address used for entitlement.

**Entry Function:**

```ts
ve_tapp::voter::claim_bribes(caller, pools, tokens, ve_token_addr)
```

***

#### Lock

**`create_lock`**

Creates a new voting escrow lock by locking `TAPP` tokens for a specified duration. This mints a new veNFT to the sender.

**Parameters:**

* `value`: `u64` - Amount of `TAPP` tokens to lock.
* `lock_duration`: `u64` - Duration of the lock in seconds.

**Entry Function:**

```ts
ve_tapp::vetapp::create_lock(sender, value, lock_duration)
```

***

**`withdraw`**

Withdraws the locked `TAPP` tokens after the lock duration has expired. The veNFT is burned upon withdrawal.

**Entry Function:**

```ts
ve_tapp::vetapp::withdraw(owner, token_addr)
```

*Note: `token_addr` is the address of the veNFT object.*

***

**`increase_amount`**

Increases the amount of `TAPP` tokens in an existing lock.

**Parameters:**

* `token_addr`: `address` - The address of the veNFT.
* `value`: `u64` - Additional amount of `TAPP` tokens to lock.

**Entry Function:**

```ts
ve_tapp::vetapp::increase_amount(caller, token_addr, value)
```

***

**`increase_unlock_time`**

Extends the unlock time of an existing lock.

**Parameters:**

* `token_addr`: `address` - The address of the veNFT.
* `lock_duration`: `u64` - Additional duration in seconds to add to the current lock.

**Entry Function:**

```ts
ve_tapp::vetapp::increase_unlock_time(owner, token_addr, lock_duration)
```

***

**`merge`**

Merges two veNFTs into one. The source veNFT is burned, and its balance and unlock time are merged into the target veNFT.

**Parameters:**

* `from_nft_addr`: `address` - The address of the veNFT to merge from (will be burned).
* `to_nft_addr`: `address` - The address of the veNFT to merge into.

**Entry Function:**

```ts
ve_tapp::vetapp::merge(sender, from_nft_addr, to_nft_addr)
```

***

**`split`**

Splits a veNFT into two. A new veNFT is minted with the specified amount, and the original veNFT's balance is reduced.

**Parameters:**

* `nft_addr`: `address` - The address of the veNFT to split.
* `value`: `u64` - Amount of `TAPP` tokens to move to the new veNFT.

**Entry Function:**

```ts
ve_tapp::vetapp::split(owner, nft_addr, value)
```

***

**`create_perm_lock`**

Creates a permanent lock. Permanent locks do not have an expiration time and cannot be withdrawn unless unlocked first.

**Parameters:**

* `value`: `u64` - Amount of `TAPP` tokens to lock.
* `lock_duration`: `u64` - Duration of the initial lock in seconds.

**Entry Function:**

```ts
ve_tapp::vetapp::create_perm_lock(sender, value, lock_duration)
```

***

**`create_lock_for`**

Creates a voting escrow lock for a recipient address instead of the sender.

**Parameters:**

* `value`: `u64` - Amount of `TAPP` tokens to lock.
* `lock_duration`: `u64` - Duration of the lock in seconds.
* `recipient`: `address` - Address that receives the veNFT.

**Entry Function:**

```ts
ve_tapp::vetapp::create_lock_for(sender, value, lock_duration, recipient)
```

***

**`create_perm_lock_for`**

Creates a permanent voting escrow lock for a recipient address.

**Parameters:**

* `value`: `u64` - Amount of `TAPP` tokens to lock.
* `lock_duration`: `u64` - Duration of the lock in seconds.
* `recipient`: `address` - Address that receives the veNFT.

**Entry Function:**

```ts
ve_tapp::vetapp::create_perm_lock_for(sender, value, lock_duration, recipient)
```

***

**`deposit_for`**

Adds more `TAPP` to an existing veNFT.

**Parameters:**

* `token_addr`: `address` - The address of the veNFT.
* `value`: `u64` - Additional amount of `TAPP` tokens to lock.

**Entry Function:**

```ts
ve_tapp::vetapp::deposit_for(sender, token_addr, value)
```

***

**`lock_permanent`**

Marks an existing veNFT as permanent.

**Parameters:**

* `token_addr`: `address` - The address of the veNFT.

**Entry Function:**

```ts
ve_tapp::vetapp::lock_permanent(owner, token_addr)
```

***

**`unlock_permanent`**

Converts a permanent lock back to a normal lock with a default expiration.

**Parameters:**

* `token_addr`: `address` - The address of the veNFT.

**Entry Function:**

```ts
ve_tapp::vetapp::unlock_permanent(owner, token_addr)
```

***

## 📌 Fee Guide

| Fee (bps) | % Fee | Description              |
| --------- | ----- | ------------------------ |
| 100       | 0.01% | Low volume, tight spread |
| 500       | 0.05% | Standard for stables     |
| 3000      | 0.3%  | Normal volatile pairs    |
| 10000     | 1%    | Exotic or risky tokens   |


---

# 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/sc.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.
