> ## Documentation Index
> Fetch the complete documentation index at: https://docs.powfi.alephium.org/llms.txt
> Use this file to discover all available pages before exploring further.

# TickUtils

> 在 CLMM 池的 tick、sqrtPriceX96 和人类可读价格之间换算。

export const VersionBanner = ({network = 'mainnet', products = [], lang = 'en'}) => {
  const SDK_VERSION = '1.0.2';
  const ADDRESSES = {
    mainnet: {
      cpmm: {
        Router: 'ze15rnAwTyVCPnDhN7J8An3SvNeWBsZHAVMeBx1ehXeP',
        TokenPairFactory: '24CXRLvj1QiDH6riwr1EPERG7BcduHKZtktygbq97MfYb'
      },
      clmm: {
        PoolFactory: '24gqd4DMQXVzjm5QDAGxUtYupx3WM2PSu3vZUseuBCV9h',
        PositionManager: 'vFyKSqnJHS9MicrojBcLgztyRFqhS4hB349Ci3LJCELw'
      },
      staking: {
        XAlphToken: '225WevmFp5ZgzPsyVJTvyp2v2uyKrvp329HfrVmzffnWj',
        RewardFeeCollector: '22CE7vG6u64zjjsLZLxeJqQuPDydjPvbP9iG1d861j2G7'
      }
    },
    testnet: {
      cpmm: {
        Router: 'xaueT8kPMvpnaFJEfHv6CJLgqsSPpoNmHjF1QgTxoF9R',
        TokenPairFactory: '29hdd9b9Gp7oXuamwHKfUqBaRXP487HoeTcutS3RhZJEj'
      },
      clmm: {
        PoolFactory: 'z2QFT7qBQrfm8UwAYG3VHWoHs7B56ZDFNdSCcDu5j53m',
        PositionManager: '21p6egW8d6FEyVVuH17WqvHCARsCsD61GcBmeCr75XdGT'
      },
      staking: {
        XAlphToken: '23psDicimC5VdpM56wrgqgCzQzcyXWGCkQGSYWbtZAPRq',
        RewardFeeCollector: '29qQ1LPJ5uqawRviXLVDMeo19JUygRrNNTQy5RUBh817D'
      }
    }
  };
  const EXPLORERS = {
    mainnet: 'https://explorer.alephium.org/addresses/',
    testnet: 'https://testnet.alephium.org/addresses/'
  };
  const LABELS = {
    en: {
      sdk: 'SDK',
      network: 'Network',
      contracts: 'Contracts',
      all: 'All addresses',
      allNetworks: 'mainnet · testnet · devnet',
      devnet: 'Local deployment (addresses vary per devnet)'
    },
    zh: {
      sdk: 'SDK 版本',
      network: '网络',
      contracts: '合约',
      all: '全部地址',
      allNetworks: 'mainnet · testnet · devnet',
      devnet: '本地部署（每个 devnet 的地址不同）'
    },
    fr: {
      sdk: 'SDK',
      network: 'Réseau',
      contracts: 'Contrats',
      all: 'Toutes les adresses',
      allNetworks: 'mainnet · testnet · devnet',
      devnet: 'Déploiement local (adresses propres à chaque devnet)'
    }
  };
  const t = LABELS[lang] ?? LABELS.en;
  const contractsPage = lang === 'en' ? '/reference/contracts' : `/${lang}/reference/contracts`;
  const short = a => `${a.slice(0, 6)}…${a.slice(-4)}`;
  const entries = [];
  const addrs = ADDRESSES[network];
  if (addrs) {
    for (const p of products) {
      for (const [name, address] of Object.entries(addrs[p] ?? ({}))) entries.push({
        name,
        address
      });
    }
  }
  let contractsCell;
  if (network === 'devnet' && products.length > 0) {
    contractsCell = <span>{t.devnet}</span>;
  } else if (entries.length > 0) {
    contractsCell = entries.map(({name, address}, i) => <span key={name}>
        {i > 0 && <span className="mx-1 opacity-50">·</span>}
        {name}{' '}
        <a href={EXPLORERS[network] + address} target="_blank" rel="noreferrer" title={address}>
          <code>{short(address)}</code>
        </a>
      </span>);
  }
  const row = (label, value) => <div className="flex flex-wrap gap-x-2">
      <span className="font-semibold min-w-[5.5rem]">{label}</span>
      <span className="flex-1 min-w-0 break-words">{value}</span>
    </div>;
  return <div className="not-prose mb-6 rounded-xl border border-zinc-950/10 dark:border-white/10 bg-zinc-50 dark:bg-white/5 px-4 py-3 text-sm leading-6 text-zinc-700 dark:text-zinc-300">
      {row(t.sdk, <code>@alephium/powfi-sdk@{SDK_VERSION}</code>)}
      {row(t.network, network === 'all' ? t.allNetworks : network)}
      {contractsCell && row(t.contracts, <span>
            {contractsCell}
            <span className="mx-1 opacity-50">·</span>
            <a href={contractsPage}>{t.all} →</a>
          </span>)}
    </div>;
};

<VersionBanner network="mainnet" products={[]} lang="zh" />

```ts theme={null}
import { TickUtils } from '@alephium/powfi-sdk'
```

CLMM 价格有三种表示方式：

| 表示方式 | 类型 | 示例 | 使用场景 |
| - | - | - | - |
| 人类可读价格 | `number` / `Decimal` | `0.25`（每个 token0 值多少 token1，已按精度调整） | 界面 |
| `sqrtPriceX96` | `bigint` | `sqrt(原始价格) × 2^96` | 池状态、兑换限价 |
| Tick | `bigint` | `价格 = 1.0001^tick` | 头寸区间 |

所有原始价格都是按排序后顺序的 **每个 token0 值多少 token1**。下面的基础/报价辅助函数可以处理界面上任意方向的交易对。

## Tick ↔ sqrtPriceX96

### `getSqrtRatioAtTick(tick)`

```ts theme={null}
static getSqrtRatioAtTick(tick: bigint): bigint
```

链上 tick 数学的精确移植。当 `|tick| > MAX_TICK`（887272）时抛出 `TickOutOfBounds`。

### `getTickAtSqrtRatio(sqrtPriceX96)`

```ts theme={null}
static getTickAtSqrtRatio(sqrtPriceX96: bigint): bigint
```

返回 sqrt 比率 ≤ 输入值的最大 tick。输入超出 `[MIN_SQRT_RATIO, MAX_SQRT_RATIO)` 时抛出 `SqrtPriceX96OutOfBounds`。

## 价格 ↔ sqrtPriceX96

### `priceToSqrtPriceX96(price, token0Decimals, token1Decimals)`

```ts theme={null}
static priceToSqrtPriceX96(price: Decimal.Value, token0Decimal: number, token1Decimal: number): bigint
```

`price` 是以 token1 计的 token0 人类可读价格。价格非有限值或非正数时抛出错误。

### `sqrtPriceX96ToPrice(sqrtPriceX96, token0Decimals, token1Decimals)`

```ts theme={null}
static sqrtPriceX96ToPrice(sqrtPriceX96: bigint, token0Decimal: number, token1Decimal: number): number
```

```ts theme={null}
const state = await powfi.clmm.getPoolState(poolId)
const price = TickUtils.sqrtPriceX96ToPrice(state.sqrtPriceX96, state.token0Info.decimals, state.token1Info.decimals)
// price of 1 token0 in token1
```

## 对齐到 tick 间距

头寸边界必须是费率档位 `tickSpacing` 的整数倍。

### `getAlignedTick(price, token0Decimals, token1Decimals, tickSpacing)`

把人类可读价格转换为最近的有效 tick（向上取整到 `tickSpacing` 的倍数）。

```ts theme={null}
const { tickSpacing } = (await powfi.clmm.getPoolConfig(configIndex))!
const tickLower = TickUtils.getAlignedTick(0.2, d0, d1, tickSpacing)
const tickUpper = TickUtils.getAlignedTick(0.3, d0, d1, tickSpacing)
```

## 面向界面的基础/报价辅助函数

这些函数按**用户看到的方式**接收代币（`tokenBase`、`tokenQuote`）以及 `baseIn`，并在内部转换为排序后的顺序。`baseIn = true` 时，价格表示为"1 个 base = X 个 quote"。

| 方法 | 返回 | 用途 |
| - | - | - |
| `getAlignedPrice(price, tokenBase, tokenQuote, tickSpacing, baseIn)` | `{ tick, price }` | 把用户输入的价格对齐到有效 tick，并显示对齐后的价格 |
| `getPriceFromTick(tick, tokenBase, tokenQuote, baseIn)` | `{ tick, price }` | 显示区间边界 |
| `getNextTick(tick, tickSpacing, tokenBase, tokenQuote, baseIn, isAdd)` | `bigint` | 价格输入框旁的 `+` / `−` 按钮 |
| `getMinPriceFromTick(tokenBase, tokenQuote, tickSpacing, baseIn)` | `{ tick, price }` | "全区间"下界 |
| `getMaxPriceFromTick(tokenBase, tokenQuote, tickSpacing, baseIn)` | `{ tick, price }` | "全区间"上界 |

```ts theme={null}
// user types "1 ALPH = 0.25 USDT" as the lower bound
const lower = TickUtils.getAlignedPrice(0.25, alphInfo, usdtInfo, tickSpacing, true)
// lower.tick -> pass to addLiquidity; lower.price -> show "0.2499…" in the input
```

## 兑换数学

| 方法 | 说明 |
| - | - |
| `getNextSqrtPrice(sqrtPX96, liquidity, amount, zeroForOne)` | 在一个流动性区间内兑换 `amount` 后的价格 |
| `getNextSqrtPriceFromAmount0(...)` / `getNextSqrtPriceFromAmount1(...)` | 区分方向的版本 |
| `getSqrtPriceX96Bounds(sqrtPriceX96, slippageBps)` | `[min, max]` = `sqrtPrice × sqrt(1 ∓ s)` |
| `getSqrtPriceLimitX96(sqrtPriceX96, slippageBps, zeroForOne)` | 传给兑换的限价。始终严格越过当前价格，并位于有效范围内。 |

## 常量

从包的根路径导出：`MIN_TICK = -887272n`、`MAX_TICK = 887272n`、`U256_MAX`、`UNLIMITED_AMOUNT` 和 `MAX_PIPS`。包的根路径**不**导出 `MIN_SQRT_RATIO`（`4295128739n`）、`MAX_SQRT_RATIO` 和 `Q96`（`2n ** 96n`），如有需要请在本地定义。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.