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

# Các demo code của LaunchLab

> TypeScript end-to-end: tạo LaunchLab launch, mua và bán trên bonding curve, nâng cấp thành pool CPMM, và thu thập phí của creator.

<Info>
  **Trang này được dịch tự động bằng AI. Phiên bản tiếng Anh là bản chính thức.**

  [Xem bản tiếng Anh →](/products/launchlab/code-demos)
</Info>

<Info>
  **Banner phiên bản.**

  * SDK: `@raydium-io/raydium-sdk-v2@0.2.42-alpha`
  * Cluster: Solana `mainnet-beta`
  * Program ID: xem [`reference/program-addresses`](/vi/reference/program-addresses)
  * Xác nhận lần cuối: 2026-04

  Ghim phiên bản SDK trong `package.json` của bạn. Interface bonding-curve đã thay đổi giữa các bản phát hành minor.
</Info>

## Thiết lập

Các demo ở đây phản ánh các file trong [`raydium-sdk-V2-demo/src/launchpad`](https://github.com/raydium-io/raydium-sdk-V2-demo/tree/master/src/launchpad). Khởi động tuân theo `config.ts.template` của repo demo:

```ts theme={null}
import { Connection, Keypair, clusterApiUrl, PublicKey } from "@solana/web3.js";
import { Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
import BN from "bn.js";
import fs from "node:fs";

const connection = new Connection(process.env.RPC_URL ?? clusterApiUrl("mainnet-beta"));
const owner = Keypair.fromSecretKey(
  new Uint8Array(JSON.parse(fs.readFileSync(process.env.KEYPAIR!, "utf8"))),
);
const raydium = await Raydium.load({
  owner,
  connection,
  cluster: "mainnet",
  disableFeatureCheck: true,
  blockhashCommitment: "finalized",
});
export const txVersion = TxVersion.V0;
```

## Tạo một launch

Nguồn: [`src/launchpad/createMint.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/launchpad/createMint.ts) (và [`createBonkMintApi.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/launchpad/createBonkMintApi.ts) cho biến thể Bonk do API điều khiển)

```ts theme={null}
import { NATIVE_MINT } from "@solana/spl-token";

const { execute, extInfo } = await raydium.launchpad.createLaunchpad({
  programId: /* LaunchLab program ID from reference/program-addresses */,
  // Token metadata for the new base mint:
  name:   "Example Token",
  symbol: "EXMPL",
  uri:    "https://example.com/metadata.json",
  decimals: 6,

  // Curve params:
  curveType: 0,                                      // 0 = quadratic
  supply:    new BN(1_000_000_000).mul(new BN(10).pow(new BN(6))), // 1B base (6 dec)
  graduationFractionBps: 8000,                       // 80% → graduation
  initialK:  new BN("40"),                           // curve shape parameter

  // Quote side:
  quoteMint: NATIVE_MINT,                            // WSOL
  openTime:  new BN(Math.floor(Date.now() / 1000) + 60),  // opens in 1min

  // Fee policy:
  fees: {
    buyNumerator:   new BN(100),                     // 1.00%
    buyDenominator: new BN(10_000),
    sellNumerator:  new BN(100),
    sellDenominator: new BN(10_000),
    lpShare:         new BN(60),
    creatorShare:    new BN(20),
    protocolShare:   new BN(20),
    totalShare:      new BN(100),
  },

  postGraduationLpPolicy: "burn",                    // "burn" | "lock" | "toCreator"

  txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Launch:", extInfo.launchState.toBase58());
console.log("Base mint:", extInfo.baseMint.toBase58());
console.log("Create tx:", txId);
```

Ghi chú:

* `initialK` là hệ số tỉ lệ cho curve bậc hai. Điều chỉnh nó để đạt được giá CPMM mở cửa cụ thể tại thời điểm nâng cấp. Xem [`products/launchlab/bonding-curve`](/vi/products/launchlab/bonding-curve) để hiểu về phần dẫn xuất.
* SDK xử lý việc tạo base mint, metadata PDA, và cả hai vault trong một transaction duy nhất. Nó có thể vượt quá 1232 byte nếu metadata URI dài; trong trường hợp đó SDK sẽ chia thành hai transaction.
* Sau `Initialize`, launch không thể giao dịch cho đến `openTime`. Đặt `openTime` trước một hoặc hai phút để giảm cơ hội cho những kẻ front-runner nắm bắt lần mua đầu tiên.

## Lấy trạng thái launch

```ts theme={null}
const launchId = new PublicKey("<LAUNCH_STATE>");

const launch = await raydium.launchpad.getLaunchById({ launchId });
console.log("Status:", ["Active","Graduated","Cancelled"][launch.status]);
console.log("Base sold:", launch.baseSold.toString(),
            "/", launch.baseSupplyMax.toString());
console.log("Quote collected:", launch.quoteReserveReal.toString(),
            "target:", launch.quoteReserveTarget.toString());
if (launch.status === 1) {
  console.log("Post-graduation CPMM pool:", launch.cpmmPoolState.toBase58());
}
```

`getLaunchById` trả về `LaunchState` được giải mã cộng với phân số "tiến độ hướng tới nâng cấp" được tính toán dưới dạng `Decimal`.

## Mua — quote chính xác đầu vào

Nguồn: [`src/launchpad/buy.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/launchpad/buy.ts)

```ts theme={null}
const quoteIn        = new BN(1).mul(new BN(10).pow(new BN(9)));  // 1 SOL
const minimumBaseOut = new BN(0);  // accept any; tighten for production

// Preview the quote off-chain so your UI can show expected base_out:
const preview = raydium.launchpad.computeBuyBase({
  launchState: launch,
  quoteIn,
});
console.log("Expected base_out:", preview.baseOut.toString(),
            "price impact:", preview.priceImpact.toString());

const { execute } = await raydium.launchpad.buyExactIn({
  launchInfo: launch,
  quoteIn,
  minimumBaseOut,
  txVersion: TxVersion.V0,
});

const { txId } = await execute({ sendAndConfirm: true });
console.log("Buy tx:", txId);
```

`computeBuyBase` phản ánh solver Newton on-chain (curve bậc hai) hoặc CPMM-inverse dạng đóng (curve\_type 1). Sử dụng nó để điền trường UI "Bạn nhận".

## Mua — chính xác base đầu ra

```ts theme={null}
const baseOut         = new BN(1_000_000).mul(new BN(10).pow(new BN(6)));  // 1M base
const maximumQuoteIn  = new BN(2).mul(new BN(10).pow(new BN(9)));          // cap at 2 SOL

const { execute } = await raydium.launchpad.buyExactOut({
  launchInfo: launch,
  baseOut,
  maximumQuoteIn,
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
```

Hữu ích cho giao diện "mua chính xác X token". Từ chối với `ExceededSlippage` nếu curve đã thay đổi đủ để yêu cầu quote hiện tại vượt quá `maximumQuoteIn`.

## Bán

Nguồn: [`src/launchpad/sell.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/launchpad/sell.ts)

```ts theme={null}
const baseIn           = new BN(500_000).mul(new BN(10).pow(new BN(6)));  // 0.5M base
const minimumQuoteOut  = new BN(0);

const { execute } = await raydium.launchpad.sellExactIn({
  launchInfo: launch,
  baseIn,
  minimumQuoteOut,
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
```

Đường bán của curve đối xứng với đường mua: giảm `base_sold` bởi `baseIn` trả về `quote_out` bằng diện tích tích phân dưới curve giữa `base_sold − baseIn` và `base_sold`, trừ phí bán.

## Tự động nâng cấp khi lần mua vượt ngưỡng

SDK nối một lệnh `Graduate` bên trong transaction `buy*` khi nó phát hiện trạng thái sau khi mua sẽ vượt ngưỡng:

```ts theme={null}
const { execute, willGraduate } = await raydium.launchpad.buyExactIn({
  launchInfo: launch,
  quoteIn: new BN(100).mul(new BN(10).pow(new BN(9))),    // large buy
  minimumBaseOut: new BN(0),
  txVersion: TxVersion.V0,
  autoGraduate: true,                                      // default
});

if (willGraduate) {
  console.log("This buy will trigger graduation.");
}

const { txId } = await execute({ sendAndConfirm: true });
```

Vì `Graduate` không cần quyền, bất kỳ ai (bao gồm MEV bot) đều có thể race để hạ cánh `Graduate` đầu tiên sau khi ngưỡng bị vượt — thường trong vài giây, không phải phút. Người hạ cánh đầu tiên chỉ trả tiền thuê cho các account pool CPMM; họ không nhận được lợi ích nào khác.

## Manual `Graduate`

Nếu `autoGraduate` tắt hoặc transaction vượt ngưỡng thất bại, bạn có thể kích hoạt nâng cấp riêng biệt:

```ts theme={null}
const { execute } = await raydium.launchpad.graduate({
  launchInfo: launch,
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
```

Hoàn nguyên với `NotAtThreshold` nếu `quote_reserve_real < quote_reserve_target` tại thời điểm gửi. Thân thiện với thử lại — một nỗ lực `Graduate` thứ hai sau khi thành công hoàn nguyên với `NotActive`.

## Thu thập phí của creator

Nguồn: [`src/launchpad/claimCreatorFee.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/launchpad/claimCreatorFee.ts) (một mint) và [`collectAllCreatorFees.ts`](https://github.com/raydium-io/raydium-sdk-V2-demo/blob/master/src/launchpad/collectAllCreatorFees.ts) (batch)

```ts theme={null}
const { execute } = await raydium.launchpad.collectCreatorFees({
  launchInfo: launch,
  txVersion: TxVersion.V0,
});

await execute({ sendAndConfirm: true });
```

Chuyển số tiền bộ đếm phí creator tích lũy đến ATA của creator trên quote mint. Có thể gọi trước hoặc sau nâng cấp; sử dụng nó định kỳ thay vì chờ một số dư khổng lồ tích tụ.

## Theo dõi launch qua vòng đời của nó

Kết hợp lại, một script giám sát có thể trông như:

```ts theme={null}
async function watch(launchId: PublicKey) {
  while (true) {
    const launch = await raydium.launchpad.getLaunchById({ launchId });
    const progress =
      Number(launch.quoteReserveReal) /
      Number(launch.quoteReserveTarget);

    console.log(
      `status=${["Active","Graduated","Cancelled"][launch.status]}`,
      `progress=${(progress * 100).toFixed(2)}%`,
      `num_buys=${launch.stateData.numBuys}`,
    );

    if (launch.status === 1) {
      console.log("Graduated to CPMM pool:", launch.cpmmPoolState.toBase58());
      break;
    }
    await new Promise(r => setTimeout(r, 10_000));
  }
}
```

## Rust CPI

Gọi LaunchLab từ chương trình Anchor của riêng bạn là hiếm (hầu hết các tích hợp launch chỉ ở phía TS). Nếu bạn làm, chương trình vận chuyển một crate Anchor `raydium_launchlab` với `cpi::accounts::Buy`, `cpi::accounts::Sell`, v.v. — mẫu phản ánh các ví dụ CPI của CPMM / CLMM. Xem [`sdk-api/rust-cpi`](/vi/sdk-api/rust-cpi) để xem mẫu tổng quát một khi trang này được điền đầy đủ.

## Những cái bẫy

* **Số học phân chia phí sai lệch một đơn vị.** Nếu `total_share` không chính xác bằng `lp_share + creator_share + protocol_share`, `Initialize` hoàn nguyên với `InvalidFeeShares`. Đặt `totalShare` bằng tổng.
* **Sử dụng quote mint không được phép.** `launch_config.allowed_quote_mints` là danh sách cố định; chuyển bất kỳ mint nào khác hoàn nguyên. Kiểm tra với `raydium.launchpad.getConfig()` trước.
* **Kích thước metadata.** Chuỗi `uri` dài đẩy CPI Metaplex vượt quá ngân sách. Giữ `uri` dưới \~200 ký tự — hầu hết metadata JSON do CDN lưu trữ phù hợp dễ dàng.
* **Graduation race.** Các bot tự động giám sát `quote_reserve_real` và front-run `Graduate` trong vòng một hoặc hai slot sau khi ngưỡng bị vượt. Điều này là lành tính — nó chỉ tốn tiền thuê cho họ — nhưng điều đó có nghĩa là UI của bạn nên coi các chuyển đổi `status` là các sự kiện nhanh chóng.

## Tiếp theo đi đâu

* [`products/launchlab/bonding-curve`](/vi/products/launchlab/bonding-curve) — toán curve.
* [`products/cpmm/code-demos`](/vi/products/cpmm/code-demos) — làm gì với pool kết quả.
* [`user-flows/launch-token-launchlab`](/vi/user-flows/launch-token-launchlab) — hướng dẫn end-to-end launch token, bao gồm các bước off-chain.

Nguồn:

* [Raydium SDK v2](https://github.com/raydium-io/raydium-sdk-V2)
* Raydium LaunchLab program source
