Добавление ликвидности в пул DeDust

Добавишь ликвидность в volatile-пул DeDust: два депозита в Vault, targetBalances и получение LP-токенов.

Ликвидность в DeDust

Чтобы стать LP в пуле DeDust, нужно внести оба актива пары. Из‑за асинхронной модели TON это два отдельных депозита в Vault. Пока оба актива не поступили, их держит контракт Liquidity Deposit; после принятия пул выпускает LP-токены.


Депозит в пул Gram / SCALE

typescript
// @dedust/sdk@0.8.7  |  @ton/ton@16.3.0  |  @ton/core@0.63.1
import {
  Factory,
  MAINNET_FACTORY_ADDR,
  Asset,
  PoolType,
  JettonRoot,
  VaultJetton,
} from "@dedust/sdk";
import { TonClient4, Address, toNano, Sender } from "@ton/ton";

// SCALE jetton master — mainnet
const SCALE_ADDRESS = Address.parse(
  "EQBlqsm144Dq6SjbPI4jjZvA1hqTIP3cFsu3ETLZNOZUh6TG",
);

const tonClient = new TonClient4({
  endpoint: "https://mainnet-v4.tonhubapi.com",
});
const factory = tonClient.open(Factory.createFromAddress(MAINNET_FACTORY_ADDR));

export async function addTonScaleLiquidity(sender: Sender) {
  const tonAmount = toNano("5"); // 5 Gram
  const scaleAmount = toNano("10"); // 10 SCALE (9 decimals)

  const TON = Asset.native();
  const SCALE = Asset.jetton(SCALE_ADDRESS);

  // Одинаковые assets и targetBalances в обоих депозитах —
  // иначе Liquidity Deposit не сматчит пару
  const assets: [Asset, Asset] = [TON, SCALE];
  const targetBalances: [bigint, bigint] = [tonAmount, scaleAmount];

  const tonVault = tonClient.open(await factory.getNativeVault());
  const scaleVault = tonClient.open(await factory.getJettonVault(SCALE_ADDRESS));

  // 1. Депозит Gram в Native Vault
  await tonVault.sendDepositLiquidity(sender, {
    poolType: PoolType.VOLATILE,
    assets,
    targetBalances,
    amount: tonAmount,
  });

  // 2. Депозит SCALE в Jetton Vault (через jetton-transfer + forward payload)
  const scaleRoot = tonClient.open(JettonRoot.createFromAddress(SCALE_ADDRESS));
  if (!sender.address) {
    throw new Error("sender.address required");
  }
  const scaleWallet = tonClient.open(await scaleRoot.getWallet(sender.address));

  await scaleWallet.sendTransfer(sender, toNano("0.5"), {
    amount: scaleAmount,
    destination: scaleVault.address,
    responseAddress: sender.address,
    forwardAmount: toNano("0.4"),
    forwardPayload: VaultJetton.createDepositLiquidityPayload({
      poolType: PoolType.VOLATILE,
      assets,
      targetBalances,
    }),
  });
}

После обоих депозитов пул минтит LP на адрес владельца. Проверить баланс LP:

typescript
const pool = tonClient.open(
  await factory.getPool(PoolType.VOLATILE, [
    Asset.native(),
    Asset.jetton(SCALE_ADDRESS),
  ]),
);
const lpWallet = tonClient.open(await pool.getWallet(sender.address!));
const lpBalance = await lpWallet.getBalance();
console.log("LP:", lpBalance.toString());

Как это работает

targetBalances — целевые количества обоих активов в одной пропорции. Оба вызова sendDepositLiquidity / jetton-transfer должны передать идентичные assets и targetBalances.

PoolType.VOLATILE — классический constant-product пул. Для стейбл-пар используй PoolType.STABLE (если пул такого типа существует для пары).

sendDepositLiquidity для нативного актива — депозит Gram в Native Vault. Сумма amount должна совпадать с соответствующей частью targetBalances.

VaultJetton.createDepositLiquidityPayload — forward-payload в jetton-transfer: Vault(SCALE) понимает, что это не обычный перевод, а вклад в ликвидность.

forwardAmount: toNano("0.4") — газ на обработку payload внутри Vault. Слишком маленький forward → депозит jetton пройдёт, но ликвидность не зачислится.

Вывод ликвидности

typescript
await lpWallet.sendBurn(sender, toNano("0.5"), {
  amount: await lpWallet.getBalance(), // полный вывод LP
});

Burn LP инициирует возврат доли резервов. Частичный вывод — передай нужное amount меньше полного баланса.

Отмена незавершённого депозита

Если внесён только один актив:

typescript
const liquidityDeposit = tonClient.open(
  await factory.getLiquidityDeposit({
    ownerAddress: sender.address!,
    poolType: PoolType.VOLATILE,
    assets,
  }),
);
await liquidityDeposit.sendCancelDeposit(sender, {});

Частые ошибки

Разные targetBalances в двух депозитах → Liquidity Deposit не соберёт пару. Копируй один и тот же массив в оба вызова.

Недостаточный forwardAmount у jetton → Gram уже в депозите, SCALE «застрял» без обработки. Отменяй через sendCancelDeposit и повторяй с большим forward (≥ 0.3–0.4 GRAM).

Пропорция не как в пуле → лишняя часть одного актива не попадёт в LP (или депозит отклонится). Читай текущие резервы пула (getReserves) и считай вторую ногу от первой.


Что дальше

Материалы gramdocs.tech носят образовательный характер и не являются финансовой, юридической или инвестиционной рекомендацией. Работа с блокчейном TON и токеном Gram связана с рисками потери средств. Правовая информация