mcpField
S
sanctum

sanctum

github.com/sendaifun其他130145 次安装13 周前更新
代码仓库

关于 sanctum

这是面向 Solana 开发者的 Sanctum 开发指南,介绍其流动性质押基础设施及 API、代币和链上程序。内容涵盖 LST 查询与兑换、质押和提现,以及 Infinity 池集成。

主要功能

  1. 01查询 LST 元数据与 APY
  2. 02获取 LST 兑换报价和交易
  3. 03存入质押账户或提现
  4. 04说明 Infinity 池与 INF 流动性
  5. 05提供 SOL 质押及收益数据示例

适用场景

  1. 01在应用中查询 LST 信息和 APY
  2. 02为 LST 兑换构建交易流程
  3. 03集成质押、即时解除质押或提现
  4. 04使用 INF 进行 Infinity 池流动性操作

安装

复制下面的命令,在终端中运行。

$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 开发指南

使用 Sanctum 构建 Solana 应用的综合指南。Sanctum 是 Solana 最大的 LST(流动性质押代币)平台,为 1,361 多种 LST 提供支持。

概述

Sanctum 在 Solana 上提供统一的流动性质押基础设施:

  • Infinity Pool:支持零滑点兑换的多 LST 流动性池
  • Router:通过质押账户路由,实现 LST 到 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(流动性质押代币)

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 个基点,提取收取 10 个基点
  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 到 LST 的兑换:

  1. StakeWrappedSol:将 SOL 质押到池中,获取 LST
  2. WithdrawWrappedSol:从储备中提取未委托的 SOL
  3. DepositStake:存入质押账户,获取 LST
  4. SwapViaStake:通过共享验证者进行路由
费用结构
操作费用
StakeWrappedSol0 个基点
WithdrawWrappedSol1 个基点
DepositStake10 个基点(输出 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

评论

支持 Markdown