ローンチタイプ
ボンディングカーブ — インデックス作成とイベント
Last updated April 9, 2026
Genesis ボンディングカーブの完全なライフサイクルをインデックスします — GPAでカーブを検出し、スワップごとのイベントをデコードし、ポーリングなしで価格と状態の変化を追跡します。
Summary
Genesisプログラムは、すべての確認済みスワップで BondingCurveSwapEvent インナーインストラクションを発行します。インデクサーはこれとGPAクエリおよびライフサイクルインストラクション追跡を組み合わせて、取引ごとにアカウントをフェッチすることなく完全なカーブ状態を再構築できます。
- GPA検出 — プログラム全体の
BondingCurveBucketV2アカウントを検索 - スワップイベント — インナーインストラクション上の識別子バイト
255。方向、金額、手数料、スワップ後のリザーブを含む - イベントからの価格 — 追加のRPC呼び出しなしにイベントデータから現在の価格を導出
- ライフサイクル追跡 — トークン作成からRaydiumグラデュエーションまでの8つの異なるイベント
プログラムID: GNS1S5J5AspKXgpjz6SvKL66kPaKWAhaGRhCqPRxii2B
すべてのボンディングカーブの検出(GPA)
GPAビルダーを使用してプログラム上のすべての BondingCurveBucketV2 アカウントを取得します — ダッシュボード、アグリゲーター、インデクサーに役立ちます。アカウントフィールドの完全なリファレンスは高度なインターナルを参照してください。
1import { getBondingCurveBucketV2GpaBuilder } from '@metaplex-foundation/genesis';
2
3const allCurves = await getBondingCurveBucketV2GpaBuilder(umi)
4 .whereField('discriminator', /* BondingCurveBucketV2 discriminator */)
5 .get();
6
7for (const curve of allCurves) {
8 console.log('Bucket PDA: ', curve.publicKey.toString());
9 console.log('Base token balance: ', curve.data.baseTokenBalance.toString());
10}
スワップイベントのデコード
すべての確認済みスワップは、識別子バイト 255 を持つ BondingCurveSwapEvent インナーインストラクションを発行します。トランザクションからデコードして、正確なスワップ後のリザーブ状態、手数料の内訳、方向を取得します。
BondingCurveSwapEventのフィールド
| フィールド | 型 | 説明 |
|---|---|---|
swapDirection | SwapDirection | SwapDirection.Buy(SOL入力、トークン出力)または SwapDirection.Sell(トークン入力、SOL出力) |
quoteTokenAmount | bigint | スワップのSOL金額(購入の入力、売却の総出力)、ラムポート単位 |
baseTokenAmount | bigint | スワップのトークン金額(購入の出力、売却の入力) |
fee | bigint | 請求されたプロトコル手数料、ラムポート単位 |
creatorFee | bigint | 請求されたクリエイター手数料、ラムポート単位(クリエイター手数料未設定の場合は0) |
baseTokenBalance | bigint | スワップ後の baseTokenBalance |
quoteTokenDepositTotal | bigint | スワップ後の quoteTokenDepositTotal |
virtualSol | bigint | 仮想SOLリザーブ(不変 — アカウントをフェッチせずに価格計算に役立つ) |
virtualTokens | bigint | 仮想トークンリザーブ(不変 — 同上) |
blockTime | bigint | スワップを含むブロックのUnixタイムスタンプ |
確認済みトランザクションからのデコード
1import { getBondingCurveSwapEventSerializer, SwapDirection } from '@metaplex-foundation/genesis';
2
3const GENESIS_PROGRAM_ID = 'GNS1S5J5AspKXgpjz6SvKL66kPaKWAhaGRhCqPRxii2B';
4const SWAP_EVENT_DISCRIMINATOR = 255;
5
6async function decodeSwapEvent(signature: string) {
7 const tx = await umi.rpc.getTransaction(signature, {
8 commitment: 'confirmed',
9 });
10
11 if (!tx) throw new Error('Transaction not found');
12
13 const serializer = getBondingCurveSwapEventSerializer();
14
15 for (const innerIx of tx.meta?.innerInstructions ?? []) {
16 for (const ix of innerIx.instructions) {
17 const programId = tx.transaction.message.accountKeys[ix.programIdIndex];
18
19 if (programId.toString() !== GENESIS_PROGRAM_ID) continue;
20
21 const data = ix.data; // Uint8Array
22 if (data[0] !== SWAP_EVENT_DISCRIMINATOR) continue;
23
24 // 識別子バイトを切り落として、デシリアライズする。
25 const [event] = serializer.deserialize(data.slice(1));
26
27 const isBuy = event.swapDirection === SwapDirection.Buy;
28 console.log('Direction: ', isBuy ? 'buy' : 'sell');
29 console.log('Quote token amount: ', event.quoteTokenAmount.toString(), 'lamports');
30 console.log('Base token amount: ', event.baseTokenAmount.toString());
31 console.log('Protocol fee: ', event.fee.toString(), 'lamports');
32 console.log('Creator fee: ', event.creatorFee.toString(), 'lamports');
33 console.log('Base balance: ', event.baseTokenBalance.toString());
34 console.log('Quote deposit total: ', event.quoteTokenDepositTotal.toString());
35
36 return event;
37 }
38 }
39
40 return null; // このトランザクションにはスワップイベントが見つからなかった。
41}
イベントからの現在の価格の追跡
取引ごとにアカウントをフェッチするのではなく、各 BondingCurveSwapEvent に含まれるスワップ後のリザーブ状態から現在の価格を導出します:
1function getPriceFromEvent(event: BondingCurveSwapEvent, bucket: BondingCurveBucketV2) {
2 // totalTokens = virtualTokens + スワップ後のbaseTokenBalance(イベントに含まれる)
3 const totalTokens = bucket.virtualTokens + event.baseTokenBalance;
4 // totalSol = virtualSol + スワップ後のquoteTokenDepositTotal(イベントに含まれる)
5 const totalSol = bucket.virtualSol + event.quoteTokenDepositTotal;
6 // 価格:SOLあたりのトークン(bigintとしてベーストークン単位あたりのラムポート)
7 return totalSol > 0n ? totalTokens / totalSol : 0n;
8}
virtualSol と virtualTokens はすべての BondingCurveSwapEvent に含まれます — イベントから価格を計算するために別途アカウントをフェッチする必要はありません。これらはカーブ作成後は不変です。
ライフサイクルイベント
Genesisプログラムのインストラクションとインナーインストラクションイベントをリスニングして、ボンディングカーブの完全なライフサイクルを追跡します。SDKを使用したスワップトランザクションの実行については、ボンディングカーブスワップ統合を参照してください。
| イベント | 説明 | 主要フィールド |
|---|---|---|
| トークン作成 | SPLトークンのミント、genesisアカウントの初期化 | baseMint、genesisAccount |
| ボンディングカーブ追加 | BondingCurveBucketV2 アカウントの作成 | bucketPda、baseTokenAllocation、virtualSol、virtualTokens |
| ファイナライズ | ローンチ設定のロック、バケットのアクティブ化 | genesisAccount |
| ライブ開始 | swapStartCondition 充足、取引開始 | bucketPda、タイムスタンプ |
| スワップ | 購入または売却の実行 | BondingCurveSwapEvent(識別子 255) |
| 売り切れ | baseTokenBalance === 0 | bucketPda、quoteTokenDepositTotal |
| グラデュエーションクランク | 流動性移行インストラクションの送信 | bucketPda、raydiumCpmmPool |
| グラデュエーション完了 | Raydium CPMMプールへの資金調達、ボンディングカーブのクローズ | cpmmPoolPda、累積SOL |
アカウント識別子とPDA導出
識別子
| アカウント | 識別子 | 説明 |
|---|---|---|
GenesisAccountV2 | アカウントタイプごとに固有 | マスター調整アカウント |
BondingCurveBucketV2 | アカウントタイプごとに固有 | ボンディングカーブAMM状態 |
BondingCurveSwapEvent | 255(インナーインストラクション) | プログラムが発行するスワップごとのイベント |
PDAシード
| PDA | シード |
|---|---|
GenesisAccountV2 | ["genesis_account_v2", baseMint, genesisIndex (u8)] |
BondingCurveBucketV2 | ["bonding_curve_bucket_v2", genesisAccount, bucketIndex (u8)] |
TypeScriptでは、Genesis SDKの findGenesisAccountV2Pda と findBondingCurveBucketV2Pda を使ってPDAを導出します。
Notes
virtualSolとvirtualTokensはすべてのBondingCurveSwapEventに含まれます — イベントから価格を計算するために別途アカウントをフェッチする必要はありません。これらはカーブ作成後は不変ですBondingCurveSwapEventの識別子は常にバイト255です — このリーディングバイトを持つGenesisプログラム上のインナーインストラクションはすべてスワップイベントですisSoldOutがtrueを返してからisGraduatedがtrueを返すまでの間、カーブは売り切れてもRaydium CPMMプールはまだ資金調達されていません。isGraduatedがプールの存在を確認するまでユーザーをRaydiumに誘導しないでくださいisGraduatedは呼び出しのたびにRPC呼び出しを行います — 毎回のレンダリングで呼び出すのではなく、インデクサーで結果をキャッシュしてください
FAQ
BondingCurveSwapEventをデコードするにはどうすればよいですか?
Genesisプログラム(GNS1S5J5AspKXgpjz6SvKL66kPaKWAhaGRhCqPRxii2B)上で、最初のデータバイトが 255 のインナーインストラクションを見つけてください。そのバイトを切り落として残りを getBondingCurveSwapEventSerializer().deserialize(data.slice(1)) に渡します。返されたオブジェクトには swapDirection、quoteTokenAmount、baseTokenAmount、fee、creatorFee、スワップ後のリザーブ状態(baseTokenBalance、quoteTokenDepositTotal、virtualSol、virtualTokens、blockTime)が含まれます。
isSoldOutとisGraduatedの違いは何ですか?
isSoldOut はローカルの同期チェックで、baseTokenBalance が 0n になるとすぐに true を返します。isGraduated は、Raydium CPMMプールがオンチェーンで作成・資金調達されているかどうかを確認する非同期RPC呼び出しです。売り切れからグラデュエーションまでの間は、isSoldOut が true でも isGraduated が false になる期間があります。isGraduated がプールの存在を確認するまでユーザーをRaydiumに誘導しないでください。
