ローンチタイプ

Launch Pool

Last updated January 31, 2026

Launch Pool はトークンローンチのための自然な価格発見メカニズムを提供します。ユーザーはウィンドウ期間中に入金し、総入金額に対する自分のシェアに比例してトークンを受け取ります。スナイピングなし、フロントランニングなし、全員にとって公平な配布です。

学べること

このガイドでは以下を説明します:

  • Launch Pool の価格設定と配布の仕組み
  • 入金ウィンドウと請求ウィンドウの設定方法
  • 資金回収のための End Behavior の設定
  • ユーザー操作:入金、引き出し、請求

概要

Launch Pool は定義されたウィンドウ期間中に入金を受け付け、その後トークンを比例配分で配布します。最終的なトークン価格は、総入金額をトークン割り当て量で割って決定されます。

  • ユーザーは入金ウィンドウ期間中に SOL を入金します(2% の手数料が適用)
  • 入金期間中は引き出しが可能です(2% の手数料)
  • トークン配布は入金シェアに比例します
  • End Behavior が集められた SOL をトレジャリー bucket にルーティングします

対象外

固定価格販売(Presale を参照)、入札ベースのオークション(Uniform Price Auction を参照)、流動性プール作成(Raydium/Orca を使用)。

クイックスタート

仕組み

  1. 特定量のトークンが Launch Pool bucket に割り当てられます
  2. ユーザーは入金ウィンドウ期間中に SOL を入金します(手数料付きで引き出し可能)
  3. ウィンドウが閉じると、入金シェアに基づいてトークンが比例配分されます

価格発見

トークン価格は総入金額から決まります:

tokenPrice = totalDeposits / tokenAllocation
userTokens = (userDeposit / totalDeposits) * tokenAllocation

例: 1,000,000 トークンが割り当てられ、総入金額が 100 SOL の場合 = 1トークンあたり 0.0001 SOL

ライフサイクル

  1. 入金期間 - ユーザーは定義されたウィンドウ期間中に SOL を入金します
  2. Transition - End Behavior が実行されます(例:集められた SOL を別の bucket に送信)
  3. 請求期間 - ユーザーは入金の重みに比例してトークンを請求します

手数料

インストラクションSolana
Deposit2%
Withdraw2%
Graduation5%

入金手数料の例:ユーザーが 10 SOL を入金すると、ユーザーの入金アカウントには 9.8 SOL がクレジットされます。

セットアップガイド

前提条件

npm install @metaplex-foundation/genesis @metaplex-foundation/umi @metaplex-foundation/umi-bundle-defaults @metaplex-foundation/mpl-toolbox

1. Genesis Account の初期化

Genesis Account はトークンを作成し、すべての配布 bucket を調整します。

initializeV2.ts
1import {
2 findGenesisAccountV2Pda,
3 genesis,
4 initializeV2,
5} from '@metaplex-foundation/genesis'
6import { mplToolbox } from '@metaplex-foundation/mpl-toolbox'
7import { generateSigner, keypairIdentity } from '@metaplex-foundation/umi'
8import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
9
10const umi = createUmi('https://api.mainnet-beta.solana.com')
11 .use(mplToolbox())
12 .use(genesis())
13
14// umi.use(keypairIdentity(yourKeypair));
15
16const baseMint = generateSigner(umi)
17const TOTAL_SUPPLY = 1_000_000_000_000_000n // 1 million tokens (9 decimals)
18
19// Store this account address for later or recreate it when needed.
20const [genesisAccount] = findGenesisAccountV2Pda(umi, {
21 baseMint: baseMint.publicKey,
22 genesisIndex: 0,
23})
24
25await initializeV2(umi, {
26 baseMint,
27 fundingMode: 0,
28 totalSupplyBaseToken: TOTAL_SUPPLY,
29 name: 'My Token',
30 symbol: 'MTK',
31 uri: 'https://example.com/metadata.json',
32}).sendAndConfirm(umi)

totalSupplyBaseToken は、すべての bucket 割り当ての合計と等しくなるようにしてください。

2. Launch Pool Bucket の追加

Launch Pool bucket は入金を収集し、トークンを比例配分で配布します。ここでタイミングを設定します。

addLaunchPoolBucket.ts
1import {
2 genesis,
3 addLaunchPoolBucketV2,
4 findLaunchPoolBucketV2Pda,
5 findUnlockedBucketV2Pda,
6} from '@metaplex-foundation/genesis'
7import { mplToolbox } from '@metaplex-foundation/mpl-toolbox'
8import { keypairIdentity, publicKey } from '@metaplex-foundation/umi'
9import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
10
11const umi = createUmi('https://api.mainnet-beta.solana.com')
12 .use(mplToolbox())
13 .use(genesis())
14
15// umi.use(keypairIdentity(yourKeypair));
16
17// Assumes genesisAccount, baseMint, and TOTAL_SUPPLY from the Initialize step.
18
19const [launchPoolBucket] = findLaunchPoolBucketV2Pda(umi, { genesisAccount, bucketIndex: 0 })
20const [unlockedBucket] = findUnlockedBucketV2Pda(umi, { genesisAccount, bucketIndex: 0 })
21
22const now = BigInt(Math.floor(Date.now() / 1000))
23const depositStart = now
24const depositEnd = now + 86400n // 24 hours
25const claimStart = depositEnd + 1n
26const claimEnd = claimStart + 604800n // 1 week
27
28await addLaunchPoolBucketV2(umi, {
29 genesisAccount,
30 baseMint: baseMint.publicKey,
31 baseTokenAllocation: TOTAL_SUPPLY,
32
33 // Timing
34 depositStartCondition: {
35 __kind: 'TimeAbsolute',
36 padding: Array(47).fill(0),
37 time: depositStart,
38 triggeredTimestamp: null,
39 },
40 depositEndCondition: {
41 __kind: 'TimeAbsolute',
42 padding: Array(47).fill(0),
43 time: depositEnd,
44 triggeredTimestamp: null,
45 },
46 claimStartCondition: {
47 __kind: 'TimeAbsolute',
48 padding: Array(47).fill(0),
49 time: claimStart,
50 triggeredTimestamp: null,
51 },
52 claimEndCondition: {
53 __kind: 'TimeAbsolute',
54 padding: Array(47).fill(0),
55 time: claimEnd,
56 triggeredTimestamp: null,
57 },
58
59 // Optional: Minimum deposit
60 minimumDepositAmount: null, // or { amount: sol(0.1).basisPoints }
61
62 // Where collected SOL goes after transition
63 endBehaviors: [
64 {
65 __kind: 'SendQuoteTokenPercentage',
66 padding: Array(4).fill(0),
67 destinationBucket: publicKey(unlockedBucket),
68 percentageBps: 10000, // 100%
69 processed: false,
70 },
71 ],
72}).sendAndConfirm(umi)

3. Unlocked Bucket の追加

Unlocked bucket は Transition 後に Launch Pool から SOL を受け取ります。

addUnlockedBucket.ts
1import {
2 addUnlockedBucketV2,
3 genesis,
4} from '@metaplex-foundation/genesis'
5import { mplToolbox } from '@metaplex-foundation/mpl-toolbox'
6import { generateSigner, keypairIdentity } from '@metaplex-foundation/umi'
7import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
8
9const umi = createUmi('https://api.mainnet-beta.solana.com')
10 .use(mplToolbox())
11 .use(genesis())
12
13// umi.use(keypairIdentity(yourKeypair));
14
15// Assumes genesisAccount, baseMint, claimStart, and claimEnd from previous steps.
16
17await addUnlockedBucketV2(umi, {
18 genesisAccount,
19 baseMint: baseMint.publicKey,
20 baseTokenAllocation: 0n,
21 recipient: umi.identity.publicKey,
22 claimStartCondition: {
23 __kind: 'TimeAbsolute',
24 padding: Array(47).fill(0),
25 time: claimStart,
26 triggeredTimestamp: null,
27 },
28 claimEndCondition: {
29 __kind: 'TimeAbsolute',
30 padding: Array(47).fill(0),
31 time: claimEnd,
32 triggeredTimestamp: null,
33 },
34 backendSigner: null,
35}).sendAndConfirm(umi)

4. ファイナライズ

すべての bucket が設定されたら、ファイナライズしてローンチを有効化します。この操作は取り消せません。

finalize.ts
1import {
2 genesis,
3 finalizeV2,
4} from '@metaplex-foundation/genesis'
5import { mplToolbox } from '@metaplex-foundation/mpl-toolbox'
6import { keypairIdentity } from '@metaplex-foundation/umi'
7import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
8
9const umi = createUmi('https://api.mainnet-beta.solana.com')
10 .use(mplToolbox())
11 .use(genesis())
12
13// umi.use(keypairIdentity(yourKeypair));
14
15// Assumes genesisAccount and baseMint from the Initialize step.
16
17await finalizeV2(umi, {
18 baseMint: baseMint.publicKey,
19 genesisAccount,
20}).sendAndConfirm(umi)

ユーザー操作

SOL のラッピング

ユーザーは入金前に SOL を wSOL にラップする必要があります。

wrapSol.ts
1import {
2 findAssociatedTokenPda,
3 createTokenIfMissing,
4 transferSol,
5 syncNative,
6 mplToolbox,
7} from '@metaplex-foundation/mpl-toolbox'
8import { WRAPPED_SOL_MINT, genesis } from '@metaplex-foundation/genesis'
9import { keypairIdentity, publicKey, sol } from '@metaplex-foundation/umi'
10import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
11
12const umi = createUmi('https://api.mainnet-beta.solana.com')
13 .use(mplToolbox())
14 .use(genesis())
15
16// umi.use(keypairIdentity(yourKeypair));
17
18const userWsolAccount = findAssociatedTokenPda(umi, {
19 owner: umi.identity.publicKey,
20 mint: WRAPPED_SOL_MINT,
21})
22
23await createTokenIfMissing(umi, {
24 mint: WRAPPED_SOL_MINT,
25 owner: umi.identity.publicKey,
26 token: userWsolAccount,
27})
28 .add(
29 transferSol(umi, {
30 destination: publicKey(userWsolAccount),
31 amount: sol(10),
32 })
33 )
34 .add(syncNative(umi, { account: userWsolAccount }))
35 .sendAndConfirm(umi)

入金

depositLaunchPool.ts
1import {
2 genesis,
3 depositLaunchPoolV2,
4 findLaunchPoolDepositV2Pda,
5 fetchLaunchPoolDepositV2,
6} from '@metaplex-foundation/genesis'
7import { mplToolbox } from '@metaplex-foundation/mpl-toolbox'
8import { keypairIdentity, sol } from '@metaplex-foundation/umi'
9import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
10
11const umi = createUmi('https://api.mainnet-beta.solana.com')
12 .use(mplToolbox())
13 .use(genesis())
14
15// umi.use(keypairIdentity(yourKeypair));
16
17// Assumes genesisAccount, launchPoolBucket, and baseMint from previous steps.
18
19await depositLaunchPoolV2(umi, {
20 genesisAccount,
21 bucket: launchPoolBucket,
22 baseMint: baseMint.publicKey,
23 amountQuoteToken: sol(10).basisPoints,
24}).sendAndConfirm(umi)
25
26// Verify
27const [depositPda] = findLaunchPoolDepositV2Pda(umi, {
28 bucket: launchPoolBucket,
29 recipient: umi.identity.publicKey,
30})
31const deposit = await fetchLaunchPoolDepositV2(umi, depositPda)
32
33console.log('Deposited (after fee):', deposit.amountQuoteToken)

同じユーザーからの複数の入金は、単一の入金アカウントに蓄積されます。

引き出し

ユーザーは入金期間中に引き出すことができます。2% の手数料が適用されます。

withdrawLaunchPool.ts
1import {
2 genesis,
3 withdrawLaunchPoolV2,
4} from '@metaplex-foundation/genesis'
5import { mplToolbox } from '@metaplex-foundation/mpl-toolbox'
6import { keypairIdentity, sol } from '@metaplex-foundation/umi'
7import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
8
9const umi = createUmi('https://api.mainnet-beta.solana.com')
10 .use(mplToolbox())
11 .use(genesis())
12
13// umi.use(keypairIdentity(yourKeypair));
14
15// Assumes genesisAccount, launchPoolBucket, and baseMint from previous steps.
16
17await withdrawLaunchPoolV2(umi, {
18 genesisAccount,
19 bucket: launchPoolBucket,
20 baseMint: baseMint.publicKey,
21 amountQuoteToken: sol(3).basisPoints,
22}).sendAndConfirm(umi)

ユーザーが残高全額を引き出すと、入金 PDA はクローズされます。

トークンの請求

入金期間が終了し、請求が開始された後:

claimLaunchPool.ts
1import {
2 genesis,
3 claimLaunchPoolV2,
4} from '@metaplex-foundation/genesis'
5import { mplToolbox } from '@metaplex-foundation/mpl-toolbox'
6import { keypairIdentity } from '@metaplex-foundation/umi'
7import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
8
9const umi = createUmi('https://api.mainnet-beta.solana.com')
10 .use(mplToolbox())
11 .use(genesis())
12
13// umi.use(keypairIdentity(yourKeypair));
14
15// Assumes genesisAccount, launchPoolBucket, and baseMint from previous steps.
16
17await claimLaunchPoolV2(umi, {
18 genesisAccount,
19 bucket: launchPoolBucket,
20 baseMint: baseMint.publicKey,
21 recipient: umi.identity.publicKey,
22}).sendAndConfirm(umi)

トークン割り当て:userTokens = (userDeposit / totalDeposits) * bucketTokenAllocation

管理者操作

Transition の実行

入金が終了した後、Transition を実行して集められた SOL を Unlocked bucket に移動します。

transitionLaunchPool.ts
1import {
2 genesis,
3 transitionV2,
4 WRAPPED_SOL_MINT,
5} from '@metaplex-foundation/genesis'
6import {
7 findAssociatedTokenPda,
8 mplToolbox,
9} from '@metaplex-foundation/mpl-toolbox'
10import { keypairIdentity } from '@metaplex-foundation/umi'
11import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
12
13const umi = createUmi('https://api.mainnet-beta.solana.com')
14 .use(mplToolbox())
15 .use(genesis())
16
17// umi.use(keypairIdentity(yourKeypair));
18
19// Assumes genesisAccount, launchPoolBucket, unlockedBucket, and baseMint from previous steps.
20
21const [unlockedBucketQuoteTokenAccount] = findAssociatedTokenPda(umi, {
22 owner: unlockedBucket,
23 mint: WRAPPED_SOL_MINT,
24})
25
26await transitionV2(umi, {
27 genesisAccount,
28 primaryBucket: launchPoolBucket,
29 baseMint: baseMint.publicKey,
30})
31 .addRemainingAccounts([
32 { pubkey: unlockedBucket, isSigner: false, isWritable: true },
33 { pubkey: unlockedBucketQuoteTokenAccount, isSigner: false, isWritable: true },
34 ])
35 .sendAndConfirm(umi)

これが重要な理由: Transition を行わないと、集められた SOL は Launch Pool bucket にロックされたままになります。ユーザーはトークンを請求できますが、チームは調達した資金にアクセスできません。

リファレンス

Time Condition

4つの条件が Launch Pool のタイミングを制御します:

条件目的
depositStartCondition入金の開始タイミング
depositEndCondition入金の終了タイミング
claimStartCondition請求の開始タイミング
claimEndCondition請求の終了タイミング

TimeAbsolute をUnixタイムスタンプと共に使用します:

const condition = {
__kind: 'TimeAbsolute',
padding: Array(47).fill(0),
time: BigInt(Math.floor(Date.now() / 1000) + 3600), // 1 hour from now
triggeredTimestamp: null,
};

End Behavior

入金期間後に集められた SOL の処理方法を定義します:

endBehaviors: [
{
__kind: 'SendQuoteTokenPercentage',
padding: Array(4).fill(0),
destinationBucket: publicKey(unlockedBucket),
percentageBps: 10000, // 100% = 10000 basis points
processed: false,
},
]

資金を複数の bucket に分割することもできます:

endBehaviors: [
{
__kind: 'SendQuoteTokenPercentage',
padding: Array(4).fill(0),
destinationBucket: publicKey(treasuryBucket),
percentageBps: 2000, // 20%
processed: false,
},
{
__kind: 'SendQuoteTokenPercentage',
padding: Array(4).fill(0),
destinationBucket: publicKey(liquidityBucket),
percentageBps: 8000, // 80%
processed: false,
},
]

状態の取得

Bucket の状態:

import { fetchLaunchPoolBucketV2 } from '@metaplex-foundation/genesis';
const bucket = await fetchLaunchPoolBucketV2(umi, launchPoolBucket);
console.log('Total deposits:', bucket.quoteTokenDepositTotal);
console.log('Deposit count:', bucket.depositCount);
console.log('Claim count:', bucket.claimCount);
console.log('Token allocation:', bucket.bucket.baseTokenAllocation);

入金の状態:

import { fetchLaunchPoolDepositV2, safeFetchLaunchPoolDepositV2 } from '@metaplex-foundation/genesis';
const deposit = await fetchLaunchPoolDepositV2(umi, depositPda); // throws if not found
const maybeDeposit = await safeFetchLaunchPoolDepositV2(umi, depositPda); // returns null
if (deposit) {
console.log('Amount deposited:', deposit.amountQuoteToken);
console.log('Claimed:', deposit.claimed);
}

注意事項

  • 2% のプロトコル手数料が入金と引き出しの両方に適用されます
  • 同じユーザーからの複数の入金は1つの入金アカウントに蓄積されます
  • ユーザーが残高全額を引き出すと、入金 PDA はクローズされます
  • End Behavior を処理するには、入金終了後に Transition を実行する必要があります
  • ユーザーは入金するために wSOL(ラップされた SOL)を保持している必要があります

FAQ

Launch Pool でトークン価格はどのように決まりますか?

価格は総入金額に基づいて自然に発見されます。最終価格は、入金された SOL の総額を割り当てられたトークン数で割った値になります。入金が多いほど、トークンあたりの暗黙の価格が高くなります。

ユーザーは入金を引き出せますか?

はい、入金期間中に引き出すことができます。システムの悪用を防ぐため、2% の引き出し手数料が適用されます。

複数回入金するとどうなりますか?

同じウォレットからの複数の入金は、単一の入金アカウントに蓄積されます。あなたの合計シェアは、合算された入金額に基づきます。

ユーザーはいつトークンを請求できますか?

入金期間が終了し、請求ウィンドウが開いた後(claimStartCondition で定義)に請求できます。End Behavior を処理するために、先に Transition を実行する必要があります。

Launch Pool と Presale の違いは何ですか?

Launch Pool は入金に基づいて自然に価格を発見し、比例配分で配布します。Presale は事前に固定価格が設定され、先着順で上限まで割り当てられます。

用語集

用語定義
Launch Pool入金ベースの配布方式で、終了時に価格が発見される
入金ウィンドウユーザーが SOL を入金・引き出しできる期間
請求ウィンドウユーザーが比例配分されたトークンを請求できる期間
End Behavior入金期間終了後に実行される自動アクション
TransitionEnd Behavior を処理し資金をルーティングするインストラクション
比例配分総入金額に対するユーザーのシェアに基づくトークン割り当て
Quote Tokenユーザーが入金するトークン(通常は wSOL)
Base Token配布されるトークン

次のステップ