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

# Ouvrir et gérer une position CLMM

> Choisir une plage de prix, dimensionner le dépôt, ajouter de la liquidité, collecter les frais et retirer.

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

<Steps>
  <Step title="Charger le pool et le palier de frais">
    ```ts theme={null}
    import { Powfi, TickUtils, ClmmLiquidityUtils, sortTokens, UNLIMITED_AMOUNT } from '@alephium/powfi-sdk'

    const powfi = Powfi.load({ networkId: 'mainnet', signer })
    const { address } = await signer.getSelectedAccount()

    const [token0, token1] = sortTokens(tokenA, tokenB)
    const configIndex = 0n
    const config = (await powfi.clmm.getPoolConfig(configIndex))!
    const poolId = powfi.clmm.getPoolId(token0, token1, configIndex)
    const state = await powfi.clmm.getPoolState(poolId)
    const d0 = state.token0Info.decimals, d1 = state.token1Info.decimals
    ```
  </Step>

  <Step title="Choisir une plage">
    Convertissez les prix lisibles (token1 par token0) en ticks alignés sur l'espacement du palier :

    ```ts theme={null}
    const tickLower = TickUtils.getAlignedTick(0.04, d0, d1, config.tickSpacing)
    const tickUpper = TickUtils.getAlignedTick(0.06, d0, d1, config.tickSpacing)
    ```

    Pour une position sur toute la plage, utilisez `TickUtils.getMinPriceFromTick` et `getMaxPriceFromTick`, qui renvoient les ticks extrêmes alignés sur l'espacement.
  </Step>

  <Step title="Dimensionner le dépôt">
    À partir du montant d'un jeton, calculez le montant correspondant de l'autre au prix actuel :

    ```ts theme={null}
    const [amount0, amount1, liquidity] = ClmmLiquidityUtils.getAmountsAndLiquidityAtSqrtPrice(
      state.sqrtPriceX96,
      TickUtils.getSqrtRatioAtTick(tickLower),
      TickUtils.getSqrtRatioAtTick(tickUpper),
      1_000n * 10n ** BigInt(d0), // user typed 1000 token0
      UNLIMITED_AMOUNT            // token1 side follows
    )
    ```

    Si le prix actuel est en dehors de la plage, la position est à un seul côté : seul du token0 est nécessaire (prix égal ou inférieur à `tickLower`), ou seul du token1 (prix au-dessus de la plage).
  </Step>

  <Step title="Ajouter de la liquidité">
    ```ts theme={null}
    const { positionId, result } = await powfi.clmm.addLiquidity({
      token0, token1, configIndex,
      tickLower, tickUpper,
      amount0, amount1,
      slippage: 100n,             // 1% price tolerance
      existingPosition: false     // true when topping up a position you already hold
    })
    ```

    Conservez le `positionId` renvoyé : les étapes suivantes l'utilisent pour lire la position, collecter et retirer. Pour compléter la même plage plus tard, passez `existingPosition: true` : le SDK joint alors le jeton de position.
  </Step>

  <Step title="Suivre les frais et la valeur">
    ```ts theme={null}
    import { ClmmContracts } from '@alephium/powfi-sdk'
    import { addressFromContractId } from '@alephium/web3'

    const pos = await ClmmContracts.Position.at(addressFromContractId(positionId)).fetchState()
    const { liquidity, tokensOwed } = pos.fields
    ```

    `tokensOwed` contient les frais déjà crédités à la position (token0, token1, récompense). La vue `positionInfo` du pool (`powfi.clmm.positionInfo`) renvoie aussi les montants de jetons et les frais actuels. Voir la [référence CLMM](/fr/modules/clmm).

    Pour valoriser la position, passez `-liquidity`, le `sqrtPriceX96` actuel et les bornes de la plage à `ClmmLiquidityUtils.getAmountsForLiquidity`.
  </Step>

  <Step title="Collecter les frais">
    ```ts theme={null}
    await powfi.clmm.collectTokens({
      token0, token1, configIndex,
      owner: address, recipient: address,
      tickLower, tickUpper,
      amount0Max: UNLIMITED_AMOUNT,
      amount1Max: UNLIMITED_AMOUNT
    })
    ```
  </Step>

  <Step title="Retirer">
    ```ts theme={null}
    const remove = (liquidity * 50n) / 100n // 50%

    await powfi.clmm.removeLiquidity({
      token0, token1, configIndex,
      owner: address,
      tickLower, tickUpper,
      liquidity: remove,
      base: 'token0',
      baseAmount: 0n,       // min token0
      otherAmountMax: 0n    // min token1 (acts as a minimum)
    })
    ```

    `removeLiquidity` collecte aussi dans la même transaction : les jetons retirés ainsi que les frais et récompenses accumulés sont envoyés à votre adresse, sans appel séparé à `collectTokens`.
  </Step>
</Steps>

## Créer un nouveau pool

N'importe qui peut créer un pool CLMM : il n'existe on-chain aucune liste blanche de créateurs ni de jetons. Avant d'en créer un, notez que :

* **Seuls les paliers de frais existants sont utilisables.** Un pool est créé dans un palier de frais (`configIndex`) déjà mis en place par l'équipe Powfi. Vous ne pouvez pas choisir vos propres frais ni votre espacement de ticks. Listez les paliers disponibles avec `getAllPoolConfigs()`.
* **Un seul pool par paire de jetons et par palier.** L'adresse du pool est dérivée de la paire et du palier : la création échoue si ce pool existe déjà.
* **Le créateur fixe le prix initial.** Le `tick` que vous passez devient le prix de départ du pool, et votre première position est mintée à ce prix. S'il est loin du prix du marché, des arbitragistes échangeront immédiatement contre votre position.
* **Les deux jetons doivent figurer dans la liste de jetons.** Le contrat accepte n'importe quel jeton, mais `getPoolState` et les méthodes associées du SDK lèvent une erreur pour les jetons absents de la [liste de jetons](/fr/modules/token).

Si `poolExists(token0, token1, configIndex)` renvoie false, créez le pool et la première position en un seul appel :

```ts theme={null}
const initialTick = TickUtils.getAlignedTick(0.05, d0, d1, config.tickSpacing)

const { poolId } = await powfi.clmm.createPool(
  configIndex, token0, token1,
  initialTick,
  amount0, amount1,
  tickLower, tickUpper
)
```

<Note>
  Pour calculer vous-même un ID de position (par exemple pour vérifier qu'un portefeuille détient déjà une plage avant d'ajouter), ne passez pas une adresse sans groupe telle quelle : l'ID obtenu serait faux. Normalisez-la d'abord avec `normalizeAddress(address, powfi.clmm.getClmmConfig().groupIndex)`, ou utilisez `PoolUtils.getPositionId(poolAddress, owner, ...)`, qui normalise pour vous.
</Note>


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