ローンチタイプ

ボンディングカーブ — インデックス作成とイベント

Last updated April 9, 2026

Genesis ボンディングカーブの完全なライフサイクルをインデックスします — GPAでカーブを検出し、スワップごとのイベントをデコードし、ポーリングなしで価格と状態の変化を追跡します。

Summary

Genesisプログラムは、すべての確認済みスワップで BondingCurveSwapEvent インナーインストラクションを発行します。インデクサーはこれとGPAクエリおよびライフサイクルインストラクション追跡を組み合わせて、取引ごとにアカウントをフェッチすることなく完全なカーブ状態を再構築できます。

  • GPA検出 — プログラム全体の BondingCurveBucketV2 アカウントを検索
  • スワップイベント — インナーインストラクション上の識別子バイト 255。方向、金額、手数料、スワップ後のリザーブを含む
  • イベントからの価格 — 追加のRPC呼び出しなしにイベントデータから現在の価格を導出
  • ライフサイクル追跡 — トークン作成からRaydiumグラデュエーションまでの8つの異なるイベント

プログラムID: GNS1S5J5AspKXgpjz6SvKL66kPaKWAhaGRhCqPRxii2B

すべてのボンディングカーブの検出(GPA)

GPAビルダーを使用してプログラム上のすべての BondingCurveBucketV2 アカウントを取得します — ダッシュボード、アグリゲーター、インデクサーに役立ちます。アカウントフィールドの完全なリファレンスは高度なインターナルを参照してください。

discover-all-curves.ts
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のフィールド

フィールド説明
swapDirectionSwapDirectionSwapDirection.Buy(SOL入力、トークン出力)または SwapDirection.Sell(トークン入力、SOL出力)
quoteTokenAmountbigintスワップのSOL金額(購入の入力、売却の総出力)、ラムポート単位
baseTokenAmountbigintスワップのトークン金額(購入の出力、売却の入力)
feebigint請求されたプロトコル手数料、ラムポート単位
creatorFeebigint請求されたクリエイター手数料、ラムポート単位(クリエイター手数料未設定の場合は0)
baseTokenBalancebigintスワップ後の baseTokenBalance
quoteTokenDepositTotalbigintスワップ後の quoteTokenDepositTotal
virtualSolbigint仮想SOLリザーブ(不変 — アカウントをフェッチせずに価格計算に役立つ)
virtualTokensbigint仮想トークンリザーブ(不変 — 同上)
blockTimebigintスワップを含むブロックのUnixタイムスタンプ

確認済みトランザクションからのデコード

decode-swap-event.ts
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 に含まれるスワップ後のリザーブ状態から現在の価格を導出します:

price-from-event.ts
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}

virtualSolvirtualTokens はすべての BondingCurveSwapEvent に含まれます — イベントから価格を計算するために別途アカウントをフェッチする必要はありません。これらはカーブ作成後は不変です。

ライフサイクルイベント

Genesisプログラムのインストラクションとインナーインストラクションイベントをリスニングして、ボンディングカーブの完全なライフサイクルを追跡します。SDKを使用したスワップトランザクションの実行については、ボンディングカーブスワップ統合を参照してください。

イベント説明主要フィールド
トークン作成SPLトークンのミント、genesisアカウントの初期化baseMintgenesisAccount
ボンディングカーブ追加BondingCurveBucketV2 アカウントの作成bucketPdabaseTokenAllocationvirtualSolvirtualTokens
ファイナライズローンチ設定のロック、バケットのアクティブ化genesisAccount
ライブ開始swapStartCondition 充足、取引開始bucketPda、タイムスタンプ
スワップ購入または売却の実行BondingCurveSwapEvent(識別子 255
売り切れbaseTokenBalance === 0bucketPdaquoteTokenDepositTotal
グラデュエーションクランク流動性移行インストラクションの送信bucketPdaraydiumCpmmPool
グラデュエーション完了Raydium CPMMプールへの資金調達、ボンディングカーブのクローズcpmmPoolPda、累積SOL

アカウント識別子とPDA導出

識別子

アカウント識別子説明
GenesisAccountV2アカウントタイプごとに固有マスター調整アカウント
BondingCurveBucketV2アカウントタイプごとに固有ボンディングカーブAMM状態
BondingCurveSwapEvent255(インナーインストラクション)プログラムが発行するスワップごとのイベント

PDAシード

PDAシード
GenesisAccountV2["genesis_account_v2", baseMint, genesisIndex (u8)]
BondingCurveBucketV2["bonding_curve_bucket_v2", genesisAccount, bucketIndex (u8)]

TypeScriptでは、Genesis SDKの findGenesisAccountV2PdafindBondingCurveBucketV2Pda を使ってPDAを導出します。

Notes

  • virtualSolvirtualTokens はすべての BondingCurveSwapEvent に含まれます — イベントから価格を計算するために別途アカウントをフェッチする必要はありません。これらはカーブ作成後は不変です
  • BondingCurveSwapEvent の識別子は常にバイト 255 です — このリーディングバイトを持つGenesisプログラム上のインナーインストラクションはすべてスワップイベントです
  • isSoldOuttrue を返してから isGraduatedtrue を返すまでの間、カーブは売り切れてもRaydium CPMMプールはまだ資金調達されていません。isGraduated がプールの存在を確認するまでユーザーをRaydiumに誘導しないでください
  • isGraduated は呼び出しのたびにRPC呼び出しを行います — 毎回のレンダリングで呼び出すのではなく、インデクサーで結果をキャッシュしてください

FAQ

BondingCurveSwapEventをデコードするにはどうすればよいですか?

Genesisプログラム(GNS1S5J5AspKXgpjz6SvKL66kPaKWAhaGRhCqPRxii2B)上で、最初のデータバイトが 255 のインナーインストラクションを見つけてください。そのバイトを切り落として残りを getBondingCurveSwapEventSerializer().deserialize(data.slice(1)) に渡します。返されたオブジェクトには swapDirectionquoteTokenAmountbaseTokenAmountfeecreatorFee、スワップ後のリザーブ状態(baseTokenBalancequoteTokenDepositTotalvirtualSolvirtualTokensblockTime)が含まれます。

isSoldOutとisGraduatedの違いは何ですか?

isSoldOut はローカルの同期チェックで、baseTokenBalance0n になるとすぐに true を返します。isGraduated は、Raydium CPMMプールがオンチェーンで作成・資金調達されているかどうかを確認する非同期RPC呼び出しです。売り切れからグラデュエーションまでの間は、isSoldOuttrue でも isGraduatedfalse になる期間があります。isGraduated がプールの存在を確認するまでユーザーをRaydiumに誘導しないでください。