mcpField
S
sanctum

sanctum

github.com/sendaifunその他130145 回インストール13 週間前に更新
リポジトリ

sanctum について

Sanctumを使ったSolanaアプリ開発向けのガイドで、リキッドステーキング基盤、API、トークン、オンチェーンプログラムを扱います。LSTの照会や交換、ステーキングと出金、Infinity Poolの統合例を掲載しています。

主な機能

  1. 01LSTのメタデータとAPYを照会
  2. 02LST交換の見積もりと取引を取得
  3. 03ステークアカウントの入金や出金
  4. 04Infinity PoolとINF流動性を解説
  5. 05SOLステーキングと利回りデータの例

活用シーン

  1. 01アプリ内でLST情報とAPYを参照
  2. 02LST交換の取引フローを構築
  3. 03ステーキングや即時解除、出金を統合
  4. 04INFを使ってInfinity Poolの流動性を操作

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sendaifun/skills --skill sanctum

インストール後、Claude Code で/sanctumを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

docs/
troubleshooting.md
examples/infinity-pool/
README.md
examples/liquidity/
README.md
examples/lst-swap/
README.md
examples/staking/
README.md
resources/
api-reference.md
lst-reference.md
program-ids.md

詳細

Sanctum 開発ガイド

Solana 最大の LST(Liquid Staking Token)プラットフォームであり、1,361 以上の LST を支える Sanctum を使用して Solana アプリケーションを構築するための包括的なガイドです。

概要

Sanctum は、Solana 上で統合されたリキッドステーキングインフラストラクチャを提供します。

  • Infinity Pool:スリッページゼロのスワップが可能なマルチ LST 流動性プール
  • Router:ステークアカウント経由で LST 間を即時スワップ
  • Reserve:LST の引き出しに対応する SOL の即時流動性
  • LST Creation:カスタムのリキッドステーキングトークンをローンチ
  • INF Token:Infinity プールの持分を表す利回り付きトークン
主な統計
  • 1,361 以上の LST に対応
  • 14 億ドル以上のスワップ取引高を実現
  • ステーカーに分配された手数料は約 8,000 SOL(100 万ドル以上)
  • パートナー:Jupiter(jupSOL)、Bybit(bbSOL)、Drift(dSOL)、crypto.com(cdcSOL)

クイックスタート

API のセットアップ
const SANCTUM_API_BASE = 'https://sanctum-api.ironforge.network';

// All endpoints require API key
const headers = {
  'Content-Type': 'application/json',
};

// Example: Get all LST metadata
const response = await fetch(
  `${SANCTUM_API_BASE}/lsts?apiKey=${API_KEY}`
);
const lsts = await response.json();
よく使われる LST アドレス
const LST_MINTS = {
  // Native SOL (wrapped)
  SOL: 'So11111111111111111111111111111111111111112',

  // Sanctum INF (Infinity pool token)
  INF: '5oVNBeEEQvYi1cX3ir8Dx5n1P7pdxydbGF2X4TxVusJm',

  // Major LSTs
  mSOL: 'mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So',      // Marinade
  jitoSOL: 'J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn', // Jito
  bSOL: 'bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1',      // BlazeStake

  // Partner LSTs
  jupSOL: 'jupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v',   // Jupiter
  bbSOL: 'bbso1MfE7KVL7DhqwZ6dVfKrD3oNV1PEykLNM4kk5dD',    // Bybit
  dSOL: 'Dso1bDeDjCQxTrWHqUUi63oBvV7Mdm6WaobLbQ7gnPQ',     // Drift

  // Other popular LSTs
  hSOL: 'he1iusmfkpAdwvxLNGV8Y1iSbj4rUy6yMhEA3fotn9A',     // Helius
  pwrSOL: 'pWrSoLAhue6jUxUMbWaY8izMhNpWfhiJk7M3Fy3p1Kt',   // Power
  laineSOL: 'LAinEtNLgpmCP9Rvsf5Hn8W6EhNiKLZQti1xfWMLy6X', // Laine
};

基本概念

1. LST(Liquid Staking Token)

LST は、流動性を維持したステーク済み SOL を表します。ステークプールを通じて SOL をステークすると、次のようになります。

  • ステークを表す LST トークンを受け取ります
  • ステークからバリデーター報酬を獲得します
  • LST は取引や DeFi での利用が可能で、SOL にスワップして戻すこともできます
2. INF トークン

INF は、Sanctum を代表する利回り付きトークンです。

  • Infinity プールが保有する複数の LST の持分を表します
  • 報酬付与型:リベースではなく、SOL に対する価値が上昇します
  • すべての LST の加重平均利回りと取引手数料を獲得します
  • ロックアップはありません。保有して報酬を獲得し、いつでもスワップできます
// INF increases in value over time
// Example: 1 INF deposited at 1.0 SOL might be worth 1.05 SOL later
const infValue = await getInfSolValue(); // Returns current INF/SOL rate
3. SOL 価値計算プログラム

LST の数量を本質的な SOL 価値に換算するオンチェーンプログラムです。

// Each LST has a dedicated calculator
const SOL_VALUE_CALCULATORS = {
  SPL: 'sp1V4h2gWorkGhVcazBc22Hfo2f5sd7jcjT4EDPrWFF',
  SanctumSpl: 'sspUE1vrh7xRoXxGsg7vR1zde2WdGtJRbyK9uRumBDy',
  SanctumSplMulti: 'ssmbu3KZxgonUtjEMCKspZzxvUQCxAFnyh1rcHUeEDo',
  Marinade: 'mare3SCyfZkAndpBRBeonETmkCCB3TJTTrz8ZN2dnhP',
  Lido: '1idUSy4MGGKyKhvjSnGZ6Zc7Q4eKQcibym4BkEEw9KR',
  wSOL: 'wsoGmxQLSvwWpuaidCApxN5kEowLe2HLQLJhCQnj4bE',
};

API リファレンス

ベース URL
https://sanctum-api.ironforge.network

すべてのエンドポイントには、クエリパラメーター apiKey が必要です。

LST メタデータの取得
// Get all LSTs
GET /lsts?apiKey={key}

// Get specific LST by mint or symbol
GET /lsts/{mintOrSymbol}?apiKey={key}

// Response
interface LstMetadata {
  symbol: string;
  mint: string;
  decimals: number;
  tokenProgram: string;
  logoUri: string;
  name: string;
  tvl: number;         // Total Value Locked
  apy: number;         // Current APY
  holders: number;
}
APY データの取得
// Get validator APYs
GET /validators/apy?apiKey={key}

// Response
interface ValidatorApy {
  [validatorId: string]: {
    avgApy: number;
    timeseries: Array<{epoch: number; apy: number}>;
  };
}

// Get LST historical APYs
GET /lsts/{mintOrSymbol}/apys?apiKey={key}&limit={n}

// Response
interface LstApyHistory {
  apys: Array<{
    epoch: number;
    epochEndTs: number;
    apy: number;
  }>;
}
LST のスワップ
// Get swap quote and unsigned transaction
GET /swap/token/order?apiKey={key}&inp={inputMint}&out={outputMint}&amt={amount}&mode={ExactIn|ExactOut}&signer={walletPubkey}&slippageBps={bps}

// Response
interface SwapOrderResponse {
  tx: string;           // Base64 encoded transaction
  inpAmt: string;       // Input amount
  outAmt: string;       // Output amount
  source: string;       // Swap source (Infinity, Router, etc.)
  feeAmt: string;       // Fee amount
  feeMint: string;      // Fee token mint
}

// Execute signed swap
POST /swap/token/execute
Body: {
  signedTx: string;     // Base64 signed transaction
  orderResponse: object; // Original order response
}

// Response
interface SwapExecuteResponse {
  txSignature: string;
}
ステークアカウントの預け入れ
// Convert native stake account to LST
GET /swap/depositStake/order?apiKey={key}&stakeAccount={pubkey}&outputLstMint={mint}&signer={wallet}

POST /swap/depositStake/execute
Body: {
  signedTx: string;
  orderResponse: object;
}
ステークアカウントへの引き出し
// Convert LST back to stake account
GET /swap/withdrawStake/order?apiKey={key}&lstMint={mint}&amount={amount}&signer={wallet}&deactivate={boolean}

POST /swap/withdrawStake/execute
Body: {
  signedTx: string;
  orderResponse: object;
}

TypeScript との統合

クライアントの完全な実装
import { Connection, PublicKey, Transaction, Keypair } from '@solana/web3.js';

class SanctumClient {
  private apiKey: string;
  private baseUrl = 'https://sanctum-api.ironforge.network';
  private connection: Connection;

  constructor(apiKey: string, connection: Connection) {
    this.apiKey = apiKey;
    this.connection = connection;
  }

  // Get all LSTs
  async getLsts(): Promise<LstMetadata[]> {
    const response = await fetch(
      `${this.baseUrl}/lsts?apiKey=${this.apiKey}`
    );
    return response.json();
  }

  // Get specific LST
  async getLst(mintOrSymbol: string): Promise<LstMetadata> {
    const response = await fetch(
      `${this.baseUrl}/lsts/${mintOrSymbol}?apiKey=${this.apiKey}`
    );
    return response.json();
  }

  // Get swap quote
  async getSwapQuote(params: {
    inputMint: string;
    outputMint: string;
    amount: string;
    mode: 'ExactIn' | 'ExactOut';
    signer: string;
    slippageBps?: number;
  }): Promise<SwapOrderResponse> {
    const url = new URL(`${this.baseUrl}/swap/token/order`);
    url.searchParams.set('apiKey', this.apiKey);
    url.searchParams.set('inp', params.inputMint);
    url.searchParams.set('out', params.outputMint);
    url.searchParams.set('amt', params.amount);
    url.searchParams.set('mode', params.mode);
    url.searchParams.set('signer', params.signer);
    if (params.slippageBps) {
      url.searchParams.set('slippageBps', params.slippageBps.toString());
    }

    const response = await fetch(url.toString());
    return response.json();
  }

  // Execute swap
  async executeSwap(
    orderResponse: SwapOrderResponse,
    signer: Keypair
  ): Promise<string> {
    // Decode and sign transaction
    const txBuffer = Buffer.from(orderResponse.tx, 'base64');
    const transaction = Transaction.from(txBuffer);
    transaction.sign(signer);

    // Send to API
    const response = await fetch(`${this.baseUrl}/swap/token/execute`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        signedTx: transaction.serialize().toString('base64'),
        orderResponse,
      }),
    });

    const result = await response.json();
    return result.txSignature;
  }

  // Swap LSTs (convenience method)
  async swapLst(params: {
    inputMint: string;
    outputMint: string;
    amount: string;
    signer: Keypair;
    slippageBps?: number;
  }): Promise<string> {
    const quote = await this.getSwapQuote({
      inputMint: params.inputMint,
      outputMint: params.outputMint,
      amount: params.amount,
      mode: 'ExactIn',
      signer: params.signer.publicKey.toBase58(),
      slippageBps: params.slippageBps || 50,
    });

    return this.executeSwap(quote, params.signer);
  }
}
使用例
const connection = new Connection('https://api.mainnet-beta.solana.com');
const sanctum = new SanctumClient(API_KEY, connection);

// Get all LSTs
const lsts = await sanctum.getLsts();
console.log(`Found ${lsts.length} LSTs`);

// Get INF token info
const inf = await sanctum.getLst('INF');
console.log(`INF APY: ${inf.apy}%`);

// Swap 1 SOL to mSOL
const signature = await sanctum.swapLst({
  inputMint: LST_MINTS.SOL,
  outputMint: LST_MINTS.mSOL,
  amount: '1000000000', // 1 SOL (9 decimals)
  signer: wallet,
  slippageBps: 50,
});
console.log('Swap TX:', signature);

// Swap mSOL to INF
const infSwap = await sanctum.swapLst({
  inputMint: LST_MINTS.mSOL,
  outputMint: LST_MINTS.INF,
  amount: '500000000', // 0.5 mSOL
  signer: wallet,
});

Infinity Pool

仕組み

Infinity は、スリッページゼロのスワップを可能にするマルチ LST 流動性プールです。

  1. SOL 価値の計算:各 LST の価値は、オンチェーンのステークプールの状態から計算されます
  2. 公正な価格設定:スワップは本質的な SOL 価値で実行されます(AMM 曲線はありません)
  3. 手数料体系:スワップごとに 8 bps、引き出しには 10 bps
  4. 手数料の分配:90% が LP(INF 保有者)に、10% がプロトコルに分配されます
流動性の追加(INF の取得)
// Deposit SOL or any LST to get INF
async function addLiquidity(
  sanctum: SanctumClient,
  lstMint: string,
  amount: string,
  signer: Keypair
): Promise<string> {
  // Swap LST/SOL for INF
  return sanctum.swapLst({
    inputMint: lstMint,
    outputMint: LST_MINTS.INF,
    amount,
    signer,
  });
}

// Example: Add 10 SOL to Infinity
const tx = await addLiquidity(
  sanctum,
  LST_MINTS.SOL,
  '10000000000',
  wallet
);
流動性の削除
// Withdraw from Infinity pool
async function removeLiquidity(
  sanctum: SanctumClient,
  outputMint: string,
  infAmount: string,
  signer: Keypair
): Promise<string> {
  // Swap INF for desired LST/SOL
  return sanctum.swapLst({
    inputMint: LST_MINTS.INF,
    outputMint: outputMint,
    amount: infAmount,
    signer,
  });
}

// Example: Withdraw to SOL
const tx = await removeLiquidity(
  sanctum,
  LST_MINTS.SOL,
  '5000000000', // 5 INF
  wallet
);

Router

スワップの仕組み

Router は、ステークアカウント経由で LST 間のスワップを可能にします。

  1. StakeWrappedSol:SOL をプールにステークし、LST を受け取ります
  2. WithdrawWrappedSol:準備金から委任解除済みの SOL を引き出します
  3. DepositStake:ステークアカウントを預け入れ、LST を受け取ります
  4. SwapViaStake:共有バリデーター経由でルーティングします
手数料体系
操作手数料
StakeWrappedSol0 bps
WithdrawWrappedSol1 bps
DepositStake10 bps(SOL での出力の場合は免除)
SwapViaStakeルートによって異なります
Jupiter との統合

Sanctum Router は Jupiter に統合されています。最適なルーティングには Jupiter SDK を使用してください。

import { Jupiter } from '@jup-ag/core';

const jupiter = await Jupiter.load({
  connection,
  cluster: 'mainnet-beta',
  user: wallet.publicKey,
});

// Jupiter automatically routes through Sanctum when optimal
const routes = await jupiter.computeRoutes({
  inputMint: new PublicKey(LST_MINTS.mSOL),
  outputMint: new PublicKey(LST_MINTS.jitoSOL),
  amount: 1_000_000_000n,
  slippageBps: 50,
});

SOL のステーキング

直接ステーキング
// Stake SOL to get LST
async function stakeSol(
  sanctum: SanctumClient,
  lstMint: string,
  solAmount: string,
  signer: Keypair
): Promise<string> {
  return sanctum.swapLst({
    inputMint: LST_MINTS.SOL,
    outputMint: lstMint,
    amount: solAmount,
    signer,
  });
}

// Stake 5 SOL for jupSOL
const tx = await stakeSol(
  sanctum,
  LST_MINTS.jupSOL,
  '5000000000',
  wallet
);
ステーキング解除(即時)
// Instant unstake via Infinity/Reserve
async function instantUnstake(
  sanctum: SanctumClient,
  lstMint: string,
  amount: string,
  signer: Keypair
): Promise<string> {
  return sanctum.swapLst({
    inputMint: lstMint,
    outputMint: LST_MINTS.SOL,
    amount,
    signer,
  });
}
遅延ステーキング解除(手数料を低減)
// Withdraw to stake account (requires epoch wait)
async function delayedUnstake(
  sanctum: SanctumClient,
  lstMint: string,
  amount: string,
  signer: Keypair,
  deactivate: boolean = true
): Promise<string> {
  const url = new URL(`${sanctum.baseUrl}/swap/withdrawStake/order`);
  url.searchParams.set('apiKey', sanctum.apiKey);
  url.searchParams.set('lstMint', lstMint);
  url.searchParams.set('amount', amount);
  url.searchParams.set('signer', signer.publicKey.toBase58());
  url.searchParams.set('deactivate', deactivate.toString());

  const response = await fetch(url.toString());
  const orderResponse = await response.json();

  return sanctum.executeSwap(orderResponse, signer);
}

データの取得

APY の取得
// Get all LST APYs
async function getLstApys(sanctum: SanctumClient): Promise<Map<string, number>> {
  const lsts = await sanctum.getLsts();
  const apyMap = new Map();

  for (const lst of lsts) {
    apyMap.set(lst.symbol, lst.apy);
  }

  return apyMap;
}

// Get specific LST historical APY
async function getLstApyHistory(
  sanctum: SanctumClient,
  lstMint: string,
  limit: number = 30
): Promise<Array<{epoch: number; apy: number}>> {
  const response = await fetch(
    `${sanctum.baseUrl}/lsts/${lstMint}/apys?apiKey=${sanctum.apiKey}&limit=${limit}`
  );
  const data = await response.json();
  return data.apys;
}
TVL の取得
// Get TVL for specific LSTs
async function getTvl(
  sanctum: SanctumClient,
  symbols: string[]
): Promise<Map<string, number>> {
  const tvlMap = new Map();

  for (const symbol of symbols) {
    const lst = await sanctum.getLst(symbol);
    tvlMap.set(symbol, lst.tvl);
  }

  return tvlMap;
}
ユーザー保有資産の取得
import { getAccount, getAssociatedTokenAddress } from '@solana/spl-token';

async function getUserLstBalances(
  connection: Connection,
  wallet: PublicKey,
  lstMints: string[]
): Promise<Map<string, bigint>> {
  const balances = new Map();

  for (const mint of lstMints) {
    try {
      const ata = await getAssociatedTokenAddress(
        new PublicKey(mint),
        wallet
      );
      const account = await getAccount(connection, ata);
      balances.set(mint, account.amount);
    } catch {
      balances.set(mint, 0n);
    }
  }

  return balances;
}

プログラム ID

コアプログラム
プログラムID説明
S Controller5ocnV1qiCgaQR8Jb8xWnVbApfaygJ8tNoZfgPwsgx9kxInfinity プールの管理
Flat Fee Pricingf1tUoNEKrDp1oeGn4zxr7bh41eN6VcfHjfrL3ZqQday手数料の計算(非推奨)
Flat Slabs1b6NRXj6ygNu1QMKXh2H9LUR2aPApAAm1UQ2DjdhNV現行の手数料プログラム
SOL Value Calculators
CalculatorID
SPLsp1V4h2gWorkGhVcazBc22Hfo2f5sd7jcjT4EDPrWFF
SanctumSplsspUE1vrh7xRoXxGsg7vR1zde2WdGtJRbyK9uRumBDy
SanctumSplMultissmbu3KZxgonUtjEMCKspZzxvUQCxAFnyh1rcHUeEDo
Marinademare3SCyfZkAndpBRBeonETmkCCB3TJTTrz8ZN2dnhP
Lido1idUSy4MGGKyKhvjSnGZ6Zc7Q4eKQcibym4BkEEw9KR
wSOLwsoGmxQLSvwWpuaidCApxN5kEowLe2HLQLJhCQnj4bE
Stake Pool Programs
ProgramID
SanctumSpl Stake PoolSP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY
SanctumSplMulti Stake PoolSPMBzsVUuoHA4Jm6KunbsotaahvVikZs1JyTW6iJvbn

Resources

Skill Structure

sanctum/
├── SKILL.md                              # This file
├── resources/
│   ├── api-reference.md                  # Complete API documentation
│   ├── lst-reference.md                  # LST addresses and metadata
│   └── program-ids.md                    # All program addresses
├── examples/
│   ├── lst-swap/README.md                # LST swap examples
│   ├── staking/README.md                 # Staking/unstaking examples
│   ├── infinity-pool/README.md           # Infinity operations
│   └── liquidity/README.md               # Add/remove liquidity
└── docs/
    └── troubleshooting.md                # Common issues

コメント