orca について
orca は、Solana と Eclipse 向けアプリを開発する人のための Orca Whirlpools SDK ガイドです。スワップ、流動性ポジション、プール管理を扱い、新旧両方の SDK の例を掲載しています。
主な機能
- 01トークンスワップと見積もり
- 02集中型・全範囲の流動性ポジション
- 03ポジションの増減、終了、手数料回収
- 04プールの作成とデータ取得
- 05Solana・Eclipse ネットワーク設定
活用シーン
- 01トークンスワップアプリの構築
- 02流動性提供とポジション管理機能の開発
- 03Whirlpools プールの作成と照会
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ sendaifun/ skills --skill orcaインストール後、Claude Code で/orcaを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
docs/troubleshooting.mdexamples/liquidity/harvest-fees.tsmanage-position.tsopen-position.tsexamples/pools/create-pool.tsexamples/swap/token-swap.tsresources/api-reference.mdprogram-addresses.mdtemplates/setup.ts詳細
Orca Whirlpools 開発ガイド
Orca は Solana と Eclipse で最も信頼されている DEX であり、Whirlpools と呼ばれる集中流動性自動マーケットメーカー(CLMM)を基盤としています。このガイドでは、取引、流動性の提供、プール管理アプリケーションを構築するための Whirlpools SDK について説明します。
概要
Orca Whirlpools は以下を提供します。
- トークンスワップ - スリッページが低く、競争力のあるレートで効率的にトークンを交換できます
- 集中流動性 - 独自の価格範囲内で流動性を提供し、資本効率を高められます
- Splash プール - 初心者向けの、シンプルな全範囲流動性の提供方法です
- ポジション管理 - 流動性ポジションの開設、増加、減少、クローズができます
- 手数料の獲得 - ポジションから取引手数料と報酬を受け取れます
- プール作成 - パーミッションレスで新しい流動性プールを作成できます
プログラム ID
| ネットワーク | プログラム ID |
|---|---|
| Solana Mainnet | whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc |
| Solana Devnet | whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc |
| Eclipse Mainnet | whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc |
| Eclipse Testnet | 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();
ティック間隔のリファレンス
ティック間隔は価格範囲の粒度を決定します。
| ティック間隔 | 用途 | 手数料階層 |
|---|---|---|
| 1 | ステーブルコイン(例:USDC/USDT) | 0.01% |
| 8 | 相関の高いペア | 0.04% |
| 64 | 標準的なペア | 0.30% |
| 128 | エキゾチック/変動の大きいペア | 1.00% |
ベストプラクティス
セキュリティ
- 秘密鍵を決して公開しない - 環境変数または安全な鍵管理を使用してください
- プールアドレスを確認する - 正当なプールとやり取りしていることを必ず確認してください
- スリッページ保護を使用する - フロントランニングを防ぐため、適切なスリッページ許容度を設定してください
- まず Devnet でテストする - Mainnet にデプロイする前に、すべての操作を検証してください
パフォーマンス
- 優先手数料を使用する - 混雑が激しいときの Mainnet トランザクションに不可欠です
- 操作をまとめる - 可能な場合は複数の命令をまとめてください
- データを事前に取得する - RPC 呼び出しを減らすため、プールとポジションのデータをキャッシュしてください
流動性の提供
- ポジションを監視する - ポジションが価格範囲外になったタイミングを追跡してください
- 戦略的にリバランスする - ポジション調整時にはガス代を考慮してください
- 定期的に手数料を獲得する - 手数料と報酬を受け取ってリターンを複利運用してください
- インパーマネントロスを理解する - 集中流動性ポジションでは 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
- @orca-so/whirlpools - New SDK
- @orca-so/whirlpools-sdk - Legacy SDK
- @orca-so/whirlpools-core - Core utilities
- @orca-so/whirlpools-client - Low-level client
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 対応