mcpField
O
orca

orca

github.com/sendaifun开发130199 次安装13 周前更新
代码仓库

关于 orca

orca 是面向 Solana 与 Eclipse 应用开发者的 Orca Whirlpools SDK 开发指南,涵盖代币交换、流动性头寸和池管理。指南包含新版与旧版 SDK 的示例及网络配置说明。

主要功能

  1. 01代币交换与报价
  2. 02集中流动性及全范围头寸
  3. 03头寸增减、关闭与费用收取
  4. 04创建流动性池并查询数据
  5. 05配置 Solana 与 Eclipse 网络

适用场景

  1. 01构建代币交换应用
  2. 02开发流动性提供与头寸管理功能
  3. 03创建并查询 Whirlpools 池

安装

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

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

安装后在 Claude Code 中输入/orca确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

docs/
troubleshooting.md
examples/liquidity/
harvest-fees.ts
manage-position.ts
open-position.ts
examples/pools/
create-pool.ts
examples/swap/
token-swap.ts
resources/
api-reference.md
program-addresses.md
templates/
setup.ts

详细介绍

Orca Whirlpools 开发指南

Orca 是 Solana 和 Eclipse 上最受信赖的 DEX,基于名为 Whirlpools 的集中流动性自动做市商(CLMM)构建。本指南介绍 Whirlpools SDK,帮助你构建交易、流动性提供和池管理应用。

概述

Orca Whirlpools 提供:

  • 代币兑换 - 高效兑换代币,滑点低且费率具有竞争力
  • 集中流动性 - 在自定义价格区间内提供流动性,提升资金效率
  • Splash 池 - 为初学者提供简单的全区间流动性
  • 头寸管理 - 开启、增加、减少和关闭流动性头寸
  • 手续费收取 - 从头寸中收取交易手续费和奖励
  • 创建池 - 无需许可即可创建新的流动性池

程序 ID

网络程序 ID
Solana 主网whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc
Solana DevnetwhirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc
Eclipse 主网whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc
Eclipse 测试网whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc

快速开始

安装

新 SDK(Solana Web3.js v2):

npm install @orca-so/whirlpools @solana/kit

旧版 SDK(Solana Web3.js v1):

npm install @orca-so/whirlpools-sdk @orca-so/common-sdk @coral-xyz/[email protected] @solana/web3.js @solana/spl-token decimal.js

核心实用工具(可选):

npm install @orca-so/whirlpools-core @orca-so/whirlpools-client
基本设置(新 SDK)
import {
  setWhirlpoolsConfig,
  setRpc,
  setPayerFromBytes
} from "@orca-so/whirlpools";
import { createSolanaRpc, devnet } from "@solana/kit";
import fs from "fs";

// Configure for Solana Devnet
await setWhirlpoolsConfig("solanaDevnet");
await setRpc("https://api.devnet.solana.com");

// Load wallet from keypair file
const keyPairBytes = new Uint8Array(
  JSON.parse(fs.readFileSync("./keypair.json", "utf8"))
);
const wallet = await setPayerFromBytes(keyPairBytes);

// Create RPC connection
const rpc = createSolanaRpc(devnet("https://api.devnet.solana.com"));

console.log("Wallet:", wallet.address);
基本设置(旧版 SDK)
import { WhirlpoolContext, buildWhirlpoolClient, ORCA_WHIRLPOOL_PROGRAM_ID } from "@orca-so/whirlpools-sdk";
import { AnchorProvider, Wallet } from "@coral-xyz/anchor";
import { Connection, Keypair } from "@solana/web3.js";
import fs from "fs";

// Setup connection
const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");

// Load wallet
const secretKey = JSON.parse(fs.readFileSync("./keypair.json", "utf8"));
const wallet = new Wallet(Keypair.fromSecretKey(new Uint8Array(secretKey)));

// Create provider and context
const provider = new AnchorProvider(connection, wallet, {});
const ctx = WhirlpoolContext.from(connection, wallet, ORCA_WHIRLPOOL_PROGRAM_ID);
const client = buildWhirlpoolClient(ctx);

console.log("Wallet:", wallet.publicKey.toString());

代币兑换

使用新 SDK 兑换
import { swap, swapInstructions, setWhirlpoolsConfig } from "@orca-so/whirlpools";
import { address } from "@solana/kit";

await setWhirlpoolsConfig("solanaMainnet");

const poolAddress = address("POOL_ADDRESS_HERE");
const inputMint = address("INPUT_TOKEN_MINT");
const amount = 1_000_000n; // Amount in smallest units
const slippageTolerance = 100; // 100 bps = 1%

// Option 1: Use the simple swap function (builds and sends)
const txId = await swap(
  rpc,
  { inputAmount: amount, mint: inputMint },
  poolAddress,
  slippageTolerance,
  wallet
);

console.log("Swap transaction:", txId);

// Option 2: Get instructions for custom transaction building
const { instructions, quote } = await swapInstructions(
  rpc,
  { inputAmount: amount, mint: inputMint },
  poolAddress,
  slippageTolerance,
  wallet
);

console.log("Expected output:", quote.tokenEstOut);
console.log("Minimum output:", quote.tokenMinOut);
console.log("Price impact:", quote.priceImpact);
精确输出兑换
// Swap to get exact output amount
const { instructions, quote } = await swapInstructions(
  rpc,
  { outputAmount: 1_000_000n, mint: outputMint },
  poolAddress,
  slippageTolerance,
  wallet
);

console.log("Max input required:", quote.tokenMaxIn);
使用旧版 SDK 兑换
import { WhirlpoolContext, swapQuoteByInputToken, buildWhirlpoolClient } from "@orca-so/whirlpools-sdk";
import { DecimalUtil, Percentage } from "@orca-so/common-sdk";
import Decimal from "decimal.js";

// Get the pool
const whirlpool = await client.getPool(poolAddress);
const whirlpoolData = whirlpool.getData();

// Get swap quote
const inputAmount = new Decimal("1.0"); // 1 token
const quote = await swapQuoteByInputToken(
  whirlpool,
  whirlpoolData.tokenMintA,
  DecimalUtil.toBN(inputAmount, 9), // 9 decimals
  Percentage.fromFraction(1, 100), // 1% slippage
  ctx.program.programId,
  ctx.fetcher
);

console.log("Estimated output:", quote.estimatedAmountOut.toString());

// Execute swap
const tx = await whirlpool.swap(quote);
const signature = await tx.buildAndExecute();
console.log("Swap signature:", signature);

提供流动性

头寸类型

集中流动性头寸:在特定价格区间内提供流动性,以提升资金效率。

全区间头寸(Splash 池):在整个价格区间内提供流动性,类似传统 AMM。

开启集中流动性头寸
import { openPosition, openPositionInstructions } from "@orca-so/whirlpools";
import { address } from "@solana/kit";

const poolAddress = address("POOL_ADDRESS");
const lowerPrice = 0.001;  // Lower bound of price range
const upperPrice = 100.0;  // Upper bound of price range
const slippageTolerance = 100; // 1%

// Specify liquidity by token amount
const param = { tokenA: 1_000_000_000n }; // 1 token with 9 decimals

// Option 1: Simple function that builds and sends
const txId = await openPosition(
  rpc,
  poolAddress,
  param,
  lowerPrice,
  upperPrice,
  slippageTolerance,
  wallet
);

// Option 2: Get instructions for custom transaction
const {
  instructions,
  quote,
  positionMint,
  initializationCost
} = await openPositionInstructions(
  rpc,
  poolAddress,
  param,
  lowerPrice,
  upperPrice,
  slippageTolerance,
  wallet
);

console.log("Position mint:", positionMint);
console.log("Token A required:", quote.tokenEstA);
console.log("Token B required:", quote.tokenEstB);
console.log("Initialization cost:", initializationCost);
开启全区间头寸
import { openFullRangePosition, openFullRangePositionInstructions } from "@orca-so/whirlpools";

const poolAddress = address("POOL_ADDRESS");
const param = { tokenA: 1_000_000_000n };
const slippageTolerance = 100;

const {
  instructions,
  quote,
  positionMint,
  callback: sendTx
} = await openFullRangePositionInstructions(
  rpc,
  poolAddress,
  param,
  slippageTolerance,
  wallet
);

console.log("Position mint:", positionMint);
console.log("Token max B:", quote.tokenMaxB);

// Send the transaction
const txId = await sendTx();
console.log("Transaction:", txId);
增加头寸流动性
import { increaseLiquidity, increaseLiquidityInstructions } from "@orca-so/whirlpools";

const positionMint = address("POSITION_MINT");
const param = { tokenA: 500_000_000n }; // Add 0.5 tokens
const slippageTolerance = 100;

const { instructions, quote } = await increaseLiquidityInstructions(
  rpc,
  positionMint,
  param,
  slippageTolerance,
  wallet
);

console.log("Additional Token A:", quote.tokenEstA);
console.log("Additional Token B:", quote.tokenEstB);
减少头寸流动性
import { decreaseLiquidity, decreaseLiquidityInstructions } from "@orca-so/whirlpools";

const positionMint = address("POSITION_MINT");
const param = { liquidity: 1000000n }; // Or use tokenA/tokenB
const slippageTolerance = 100;

const { instructions, quote } = await decreaseLiquidityInstructions(
  rpc,
  positionMint,
  param,
  slippageTolerance,
  wallet
);

console.log("Token A received:", quote.tokenEstA);
console.log("Token B received:", quote.tokenEstB);
收取手续费和奖励
import { harvestPosition, harvestPositionInstructions, harvestAllPositionFees } from "@orca-so/whirlpools";

// Harvest single position
const positionMint = address("POSITION_MINT");

const { instructions, feesQuote, rewardsQuote } = await harvestPositionInstructions(
  rpc,
  positionMint,
  wallet
);

console.log("Fee Token A:", feesQuote.feeOwedA);
console.log("Fee Token B:", feesQuote.feeOwedB);
console.log("Rewards:", rewardsQuote);

// Harvest all positions at once
const { instructions: harvestAllIx, fees, rewards } = await harvestAllPositionFees(
  rpc,
  wallet.address
);
关闭头寸
import { closePosition, closePositionInstructions } from "@orca-so/whirlpools";

const positionMint = address("POSITION_MINT");
const slippageTolerance = 100;

const { instructions, quote, feesQuote } = await closePositionInstructions(
  rpc,
  positionMint,
  slippageTolerance,
  wallet
);

console.log("Token A returned:", quote.tokenEstA);
console.log("Token B returned:", quote.tokenEstB);
console.log("Fees collected:", feesQuote);

池管理

创建 Splash 池(全区间)
import { createSplashPool, createSplashPoolInstructions } from "@orca-so/whirlpools";
import { address } from "@solana/kit";

const tokenMintA = address("TOKEN_A_MINT");
const tokenMintB = address("TOKEN_B_MINT");
const initialPrice = 1.5; // Price of token B in terms of token A

const {
  instructions,
  poolAddress,
  initializationCost
} = await createSplashPoolInstructions(
  rpc,
  tokenMintA,
  tokenMintB,
  initialPrice,
  wallet
);

console.log("Pool address:", poolAddress);
console.log("Initialization cost:", initializationCost, "lamports");
创建集中流动性池
import { createConcentratedLiquidityPool, createConcentratedLiquidityPoolInstructions } from "@orca-so/whirlpools";

const tokenMintA = address("TOKEN_A_MINT");
const tokenMintB = address("TOKEN_B_MINT");
const tickSpacing = 64; // Common values: 1, 8, 64, 128
const initialPrice = 1.5;

const {
  instructions,
  poolAddress,
  initializationCost
} = await createConcentratedLiquidityPoolInstructions(
  rpc,
  tokenMintA,
  tokenMintB,
  tickSpacing,
  initialPrice,
  wallet
);

console.log("Pool address:", poolAddress);
获取池数据
import {
  fetchSplashPool,
  fetchConcentratedLiquidityPool,
  fetchWhirlpoolsByTokenPair
} from "@orca-so/whirlpools";

// Fetch specific pool
const pool = await fetchConcentratedLiquidityPool(rpc, poolAddress);
console.log("Current price:", pool.price);
console.log("Liquidity:", pool.liquidity);
console.log("Fee rate:", pool.feeRate);

// Fetch all pools for a token pair
const pools = await fetchWhirlpoolsByTokenPair(rpc, tokenMintA, tokenMintB);
for (const pool of pools) {
  console.log("Pool:", pool.address, "Tick spacing:", pool.tickSpacing);
}
获取头寸
import { fetchPositionsForOwner, fetchPositionsInWhirlpool } from "@orca-so/whirlpools";

// Get all positions owned by a wallet
const positions = await fetchPositionsForOwner(rpc, wallet.address);
for (const position of positions) {
  console.log("Position:", position.positionMint);
  console.log("Liquidity:", position.liquidity);
  console.log("Lower tick:", position.tickLowerIndex);
  console.log("Upper tick:", position.tickUpperIndex);
}

// Get all positions in a specific pool
const poolPositions = await fetchPositionsInWhirlpool(rpc, poolAddress);

SDK 配置

网络配置
import { setWhirlpoolsConfig } from "@orca-so/whirlpools";

// Built-in presets
await setWhirlpoolsConfig("solanaMainnet");
await setWhirlpoolsConfig("solanaDevnet");
await setWhirlpoolsConfig("eclipseMainnet");
await setWhirlpoolsConfig("eclipseTestnet");

// Custom configuration
await setWhirlpoolsConfig({
  whirlpoolsConfigAddress: address("CUSTOM_CONFIG_ADDRESS"),
  // ... other custom settings
});
交易设置
import {
  setRpc,
  setPriorityFeeSetting,
  setJitoTipSetting,
  setComputeUnitMarginMultiplier,
  setDefaultSlippageToleranceBps,
  setDefaultFunder,
  setNativeMintWrappingStrategy
} from "@orca-so/whirlpools";

// Set RPC endpoint
await setRpc("https://api.mainnet-beta.solana.com");

// Configure priority fees
await setPriorityFeeSetting({
  type: "dynamic",
  percentile: 75, // Use 75th percentile of recent fees
});

// Or set fixed priority fee
await setPriorityFeeSetting({
  type: "fixed",
  microLamports: 10000,
});

// Configure Jito tips for MEV protection
await setJitoTipSetting({
  type: "dynamic",
  percentile: 50,
});

// Set compute unit margin (for larger transactions)
await setComputeUnitMarginMultiplier(1.2);

// Set default slippage tolerance (in bps)
await setDefaultSlippageToleranceBps(100); // 1%

// Set default funder for transactions
await setDefaultFunder(wallet);

// Configure SOL wrapping behavior
await setNativeMintWrappingStrategy("ata"); // or "none"
重置配置
import { resetConfiguration } from "@orca-so/whirlpools";

// Reset all settings to defaults
await resetConfiguration();

Tick 间距参考

Tick 间距决定了价格区间的粒度:

Tick 间距用例费率等级
1稳定币(例如 USDC/USDT)0.01%
8相关性较高的交易对0.04%
64标准交易对0.30%
128冷门/高波动交易对1.00%

最佳实践

安全
  1. 切勿暴露私钥 - 使用环境变量或安全的密钥管理方式
  2. 验证池地址 - 务必确认你交互的是合法池
  3. 使用滑点保护 - 设置合适的滑点容差,防止抢先交易
  4. 先在 devnet 上测试 - 在部署到主网之前验证所有操作
性能
  1. 使用优先费用 - 主网拥堵严重时,这对交易至关重要
  2. 批量操作 - 尽可能合并多条指令
  3. 预先获取数据 - 缓存池和头寸数据,减少 RPC 调用
提供流动性
  1. 监控头寸 - 跟踪头寸何时超出价格区间
  2. 策略性地重新平衡 - 调整头寸时考虑 Gas 费用
  3. 定期收取 - 收取手续费和奖励以复利增值
  4. 了解无常损失 - 集中流动性头寸的 IL 风险更高
错误处理
try {
  const txId = await swap(rpc, swapParams, poolAddress, slippage, wallet);
} catch (error) {
  if (error.message.includes("SlippageExceeded")) {
    console.error("Slippage tolerance exceeded, try increasing slippage");
  } else if (error.message.includes("InsufficientFunds")) {
    console.error("Not enough tokens in wallet");
  } else if (error.message.includes("TickArrayNotInitialized")) {
    console.error("Price range tick arrays not initialized");
  } else {
    throw error;
  }
}

资源

官方文档
GitHub Repositories
NPM Packages
Security Audits
  • Kudelski Security audit
  • Neodyme audit

Skill Structure

orca/
├── SKILL.md                              # This file
├── resources/
│   ├── api-reference.md                  # Complete SDK function reference
│   └── program-addresses.md              # Program IDs and common pool addresses
├── examples/
│   ├── swap/
│   │   └── token-swap.ts                 # Token swap examples
│   ├── liquidity/
│   │   ├── open-position.ts              # Open liquidity positions
│   │   ├── manage-position.ts            # Increase/decrease liquidity
│   │   └── harvest-fees.ts               # Collect fees and rewards
│   └── pools/
│       └── create-pool.ts                # Pool creation examples
├── templates/
│   └── setup.ts                          # Ready-to-use client template
└── docs/
    └── troubleshooting.md                # Common issues and solutions

评论

支持 Markdown