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

# 数量与滑点

> bigint 单位、代币精度、基点，以及两种池如何应用滑点。

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={['cpmm', 'clmm']} lang="zh" />

## 数量都是原始 bigint

SDK 接收和返回的所有数量都是代币**最小单位**的 `bigint`，与链上存储的值完全一致：

| 代币 | 精度 | `1.5` 个代币对应的 bigint |
| - | - | - |
| ALPH | 18 | `1_500_000_000_000_000_000n` |
| 6 位精度的稳定币 | 6 | `1_500_000n` |

精度可以从代币列表获取（`(await powfi.token.getTokenById(id)).decimals`），也可以从池状态获取（`state.token0Info.decimals`）。

用 [`NumericUtils`](/zh/utilities/math) 进行换算：

```ts theme={null}
import { NumericUtils } from '@alephium/powfi-sdk'
import Decimal from 'decimal.js'

// human -> raw
const raw = NumericUtils.numericToBigInt(new Decimal('1.5').mul(new Decimal(10).pow(18)))

// raw -> human
NumericUtils.scaleToString(1_500_000_000_000_000_000n, 18) // "1.5"
```

`@alephium/web3` 也导出了 `convertAmountWithDecimals` 和 `prettifyTokenAmount`，用途相同。

<Warning>
  不要用 JavaScript 的 `number` 表示数量。18 位精度的数量几乎立刻就会超过 `Number.MAX_SAFE_INTEGER`，而且 SDK 的类型要求使用 `bigint`。
</Warning>

## 基点

滑点以**基点**（`bps`）表示，类型为 `bigint`，其中 `BPS = 10_000n`：

| `slippageBps` | 容忍度 |
| - | - |
| `10n` | 0.1% |
| `50n` | 0.5% |
| `100n` | 1% |
| `500n` | 5% |

有效值需满足 `0n <= slippage < 10_000n`，否则会抛出错误。

## CPMM：滑点作用于数量

CPMM 报价把滑点应用在你**没有固定**的那个数量上：

```ts theme={null}
// exact-in: minimum you accept to receive
CpmmModule.minimalAmount(amount, slippageBps) // = amount * 10000 / (10000 + slippageBps)

// exact-out: maximum you accept to pay (rounded up)
CpmmModule.maximalAmount(amount, slippageBps) // = ceil(amount * (10000 + slippageBps) / 10000)
```

`computeSwapAmount` 会填充 `minimalTokenOutAmount`（精确输入）或 `maximalTokenInAmount`（精确输出），另一个字段为 `undefined`。

<Note>
  `minimalAmount` 的计算是除以 `(1 + s)`，而不是乘以 `(1 − s)`。对于 0.5% 的滑点，结果是 99.5025% 而不是 99.5%：略微更严格，并且让 `minimalAmount` 和 `maximalAmount` 互为精确的逆运算。
</Note>

向已有的池添加流动性时，两个期望数量都会应用 `minimalAmount`。向空池进行**首次**存入时不应用滑点，因为首次存入者决定价格。

## CLMM：滑点作用于价格

CLMM 操作把滑点转换为一个**平方根价格限制**。如果池价格会越过这个限制，兑换会停止（添加流动性则会回滚）：

```ts theme={null}
TickUtils.getSqrtPriceX96Bounds(sqrtPriceX96, slippageBps)
// => [ sqrtPriceX96 * sqrt(1 - s), sqrtPriceX96 * sqrt(1 + s) ]

TickUtils.getSqrtPriceLimitX96(sqrtPriceX96, slippageBps, zeroForOne)
// zeroForOne (price goes down) -> lower bound; otherwise -> upper bound
// always strictly beyond the current price and inside [MIN_SQRT_RATIO, MAX_SQRT_RATIO]
```

所以 CLMM 兑换中 1% 的滑点意味着"池价格最多可以变动 1%"。对于在狭窄区间内的大额交易，这仍可能导致输出数量相差很大。请始终用你自己的最小值检查模拟得到的输出。

## 价格影响

`CpmmSwapQuote.priceImpact` 是一个**百分比**数字（例如 `0.42` 表示 0.42%），根据交易前后的储备量计算。`cpmm.swap` 会拒绝 `priceImpact >= 5`（`MAX_PRICE_IMPACT`）的交易。

## 手续费

| 池 | 兑换手续费 | 单位 |
| - | - | - |
| CPMM | 0.3%（`997 / 1000`） | 固定 |
| CLMM | 按费率档位：池配置中的 `tradingFee` | pips，`MAX_PIPS = 1_000_000n`（所以 `3000n` = 0.3%） |

## 截止时间

CPMM 的写入方法接受 `ttlMinutes`（默认 `60`）。SDK 会把它转换为毫秒时间戳（`Date.now() + ttl`），超过该时间后路由合约会拒绝交易。

## ALPH 押金与粉尘

在 Alephium 上，携带代币的输出必须持有最少数量的 ALPH（`DUST_AMOUNT`），新合约需要 `MINIMAL_CONTRACT_DEPOSIT`。SDK 会自动附加相应数量的 ALPH。例如，CPMM 兑换会在输入之外额外附加 2–3 倍的 `DUST_AMOUNT`，创建 CPMM 池会附加 1 ALPH 作为合约押金。请在发送方余额中为此以及 gas 预留一些 ALPH。


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