sanctum について
Sanctumを使ったSolanaアプリ開発向けのガイドで、リキッドステーキング基盤、API、トークン、オンチェーンプログラムを扱います。LSTの照会や交換、ステーキングと出金、Infinity Poolの統合例を掲載しています。
主な機能
- 01LSTのメタデータとAPYを照会
- 02LST交換の見積もりと取引を取得
- 03ステークアカウントの入金や出金
- 04Infinity PoolとINF流動性を解説
- 05SOLステーキングと利回りデータの例
活用シーン
- 01アプリ内でLST情報とAPYを参照
- 02LST交換の取引フローを構築
- 03ステーキングや即時解除、出金を統合
- 04INFを使ってInfinity Poolの流動性を操作
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ sendaifun/ skills --skill sanctumインストール後、Claude Code で/sanctumを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
docs/troubleshooting.mdexamples/infinity-pool/README.mdexamples/liquidity/README.mdexamples/lst-swap/README.mdexamples/staking/README.mdresources/api-reference.mdlst-reference.mdprogram-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 流動性プールです。
- SOL 価値の計算:各 LST の価値は、オンチェーンのステークプールの状態から計算されます
- 公正な価格設定:スワップは本質的な SOL 価値で実行されます(AMM 曲線はありません)
- 手数料体系:スワップごとに 8 bps、引き出しには 10 bps
- 手数料の分配: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 間のスワップを可能にします。
- StakeWrappedSol:SOL をプールにステークし、LST を受け取ります
- WithdrawWrappedSol:準備金から委任解除済みの SOL を引き出します
- DepositStake:ステークアカウントを預け入れ、LST を受け取ります
- SwapViaStake:共有バリデーター経由でルーティングします
手数料体系
| 操作 | 手数料 |
|---|---|
| StakeWrappedSol | 0 bps |
| WithdrawWrappedSol | 1 bps |
| DepositStake | 10 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 Controller | 5ocnV1qiCgaQR8Jb8xWnVbApfaygJ8tNoZfgPwsgx9kx | Infinity プールの管理 |
| Flat Fee Pricing | f1tUoNEKrDp1oeGn4zxr7bh41eN6VcfHjfrL3ZqQday | 手数料の計算(非推奨) |
| Flat Slab | s1b6NRXj6ygNu1QMKXh2H9LUR2aPApAAm1UQ2DjdhNV | 現行の手数料プログラム |
SOL Value Calculators
| Calculator | ID |
|---|---|
| SPL | sp1V4h2gWorkGhVcazBc22Hfo2f5sd7jcjT4EDPrWFF |
| SanctumSpl | sspUE1vrh7xRoXxGsg7vR1zde2WdGtJRbyK9uRumBDy |
| SanctumSplMulti | ssmbu3KZxgonUtjEMCKspZzxvUQCxAFnyh1rcHUeEDo |
| Marinade | mare3SCyfZkAndpBRBeonETmkCCB3TJTTrz8ZN2dnhP |
| Lido | 1idUSy4MGGKyKhvjSnGZ6Zc7Q4eKQcibym4BkEEw9KR |
| wSOL | wsoGmxQLSvwWpuaidCApxN5kEowLe2HLQLJhCQnj4bE |
Stake Pool Programs
| Program | ID |
|---|---|
| SanctumSpl Stake Pool | SP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY |
| SanctumSplMulti Stake Pool | SPMBzsVUuoHA4Jm6KunbsotaahvVikZs1JyTW6iJvbn |
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
コメント
Markdown 対応