mcpField
J
jupiter-swap-integration

jupiter-swap-integration

github.com/sanctifiedops开发347 次安装40 周前更新
代码仓库

关于 jupiter-swap-integration

面向 Jupiter Swap 集成开发的技能指南,涵盖报价、交易构建与发送,以及滑点、费用和错误处理。适用于构建兑换界面、交易 Bot 或后端服务。

主要功能

  1. 01Jupiter API 报价流程
  2. 02构建并发送 V0 交易
  3. 03按代币类型设置滑点
  4. 04优先费策略
  5. 05重试与限流处理
  6. 06兑换界面与 Bot 模板

适用场景

  1. 01开发 SOL 与其他代币的兑换功能
  2. 02为交易 Bot 配置滑点和重试
  3. 03处理网络拥堵时的优先费
  4. 04构建带状态提示的兑换界面

安装

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

$npx skills add https://github.com/sanctifiedops/solana-skills --skill jupiter-swap-integration

安装后在 Claude Code 中输入/jupiter-swap-integration确认已加载。

详细介绍

Jupiter 兑换集成

角色定位:你是一名 Jupiter 集成专家,负责构建兑换界面和交易机器人。你的目标是实现可靠、高效的兑换,并妥善处理错误、提供良好的用户体验。

初步评估

  • 你要构建什么:前端兑换 UI、交易机器人还是后端服务?
  • 预期交易量:普通用户兑换还是高频交易?
  • 代币类型:主流代币(SOL/USDC)还是长尾迷因币?
  • 滑点容忍度要求:严格(0.5%)还是宽松(5% 以上)?
  • 是否需要高级功能:限价单、DCA,还是只需现货兑换?
  • 你的 RPC 配置是什么:公共端点还是专用服务提供商?
  • 错误处理要求:重试逻辑、回退策略?

核心原则

  • Jupiter 聚合路由,但不执行交易:它会在各个 DEX 中寻找最佳路径;交易需要由你提交。
  • 滑点是保护措施,不是建议:根据波动性设置;过于严格会导致交易失败,过于宽松则会造成成交价格不佳。
  • 优先费必不可少:没有优先费,网络拥堵时兑换会失败。预算为 0.0001-0.001 SOL。
  • 报价 ≠ 保证成交:价格会变动;始终使用 onlyDirectRoutes: false,以获得更好的成交结果。
  • 存在速率限制:免费套餐为每分钟 60 次请求;付费套餐的上限更高。尽可能缓存报价。
  • 需要使用版本化交易:Jupiter 返回 V0 交易;确保你的钱包/SDK 能够处理这些交易。

工作流

1. API 设置与身份验证
// Base URLs
const JUPITER_API = 'https://quote-api.jup.ag/v6';
const JUPITER_PRICE_API = 'https://price.jup.ag/v6';

// No API key required for basic usage
// For high volume, contact Jupiter for dedicated endpoints

// Rate limits (free tier):
// - Quote API: 60 requests/minute
// - Price API: 600 requests/minute
2. 获取报价
interface QuoteParams {
  inputMint: string;      // Token to sell
  outputMint: string;     // Token to buy
  amount: string;         // Amount in smallest units (lamports/base units)
  slippageBps: number;    // Slippage in basis points (100 = 1%)
  onlyDirectRoutes?: boolean;  // false = better routes, true = simpler
  asLegacyTransaction?: boolean; // false = versioned tx (recommended)
}

async function getQuote(params: QuoteParams) {
  const url = new URL(`${JUPITER_API}/quote`);
  url.searchParams.set('inputMint', params.inputMint);
  url.searchParams.set('outputMint', params.outputMint);
  url.searchParams.set('amount', params.amount);
  url.searchParams.set('slippageBps', params.slippageBps.toString());

  const response = await fetch(url.toString());
  if (!response.ok) {
    throw new Error(`Quote failed: ${response.status}`);
  }
  return response.json();
}

// Example: Swap 1 SOL to USDC
const quote = await getQuote({
  inputMint: 'So11111111111111111111111111111111111111112', // SOL
  outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
  amount: '1000000000', // 1 SOL in lamports
  slippageBps: 50, // 0.5%
});

// Quote response includes:
// - inAmount: input amount
// - outAmount: expected output (before slippage)
// - otherAmountThreshold: minimum output (after slippage)
// - routePlan: array of swap steps
// - priceImpactPct: price impact percentage
3. 构建兑换交易
interface SwapParams {
  quoteResponse: any;
  userPublicKey: string;
  wrapAndUnwrapSol?: boolean;  // true = auto wrap/unwrap SOL
  computeUnitPriceMicroLamports?: number; // priority fee
  dynamicComputeUnitLimit?: boolean; // auto-size compute
}

async function getSwapTransaction(params: SwapParams) {
  const response = await fetch(`${JUPITER_API}/swap`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      quoteResponse: params.quoteResponse,
      userPublicKey: params.userPublicKey,
      wrapAndUnwrapSol: params.wrapAndUnwrapSol ?? true,
      computeUnitPriceMicroLamports: params.computeUnitPriceMicroLamports ?? 1000,
      dynamicComputeUnitLimit: params.dynamicComputeUnitLimit ?? true,
    }),
  });

  const { swapTransaction } = await response.json();
  return swapTransaction; // Base64 encoded versioned transaction
}
4. 签名并发送交易
import { VersionedTransaction, Connection } from '@solana/web3.js';

async function executeSwap(
  swapTransaction: string,
  wallet: any, // Wallet adapter
  connection: Connection
) {
  // Decode the transaction
  const txBuffer = Buffer.from(swapTransaction, 'base64');
  const tx = VersionedTransaction.deserialize(txBuffer);

  // Sign with wallet
  const signedTx = await wallet.signTransaction(tx);

  // Send with retry logic
  const signature = await connection.sendTransaction(signedTx, {
    skipPreflight: false,
    maxRetries: 3,
  });

  // Confirm transaction
  const confirmation = await connection.confirmTransaction(signature, 'confirmed');

  if (confirmation.value.err) {
    throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`);
  }

  return signature;
}
5. 按代币类型制定滑点策略
代币类型建议滑点原因
SOL/USDC0.1-0.3%流动性深厚且稳定
主流代币(JUP、BONK)0.5-1%流动性良好
中市值迷因币1-3%流动性不稳定
新代币/低市值代币3-10%流动性稀薄、波动较大
Pump.fun 代币5-15%波动极大
6. 优先费策略
// Estimate priority fee based on network conditions
async function estimatePriorityFee(connection: Connection): Promise<number> {
  const recentFees = await connection.getRecentPrioritizationFees();

  if (recentFees.length === 0) return 1000; // default 1000 micro-lamports

  // Use 75th percentile for reliability
  const sorted = recentFees.map(f => f.prioritizationFee).sort((a, b) => a - b);
  const p75Index = Math.floor(sorted.length * 0.75);

  return Math.max(sorted[p75Index], 1000);
}

// Priority fee tiers:
// - 1,000 micro-lamports: Normal conditions
// - 10,000 micro-lamports: Moderate congestion
// - 100,000 micro-lamports: High congestion
// - 1,000,000+ micro-lamports: Extreme (minting events, etc.)
7. 错误处理与重试
async function swapWithRetry(
  params: SwapParams,
  maxRetries: number = 3
): Promise<string> {
  let lastError: Error | null = null;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      // Get fresh quote (prices change)
      const quote = await getQuote(params.quoteParams);

      // Check if price moved too much
      if (quote.priceImpactPct > 5) {
        throw new Error(`Price impact too high: ${quote.priceImpactPct}%`);
      }

      // Get swap transaction
      const swapTx = await getSwapTransaction({
        quoteResponse: quote,
        userPublicKey: params.userPublicKey,
        computeUnitPriceMicroLamports: params.priorityFee * attempt, // Increase fee on retry
      });

      // Execute
      return await executeSwap(swapTx, params.wallet, params.connection);

    } catch (error: any) {
      lastError = error;

      // Don't retry on certain errors
      if (error.message.includes('insufficient funds')) throw error;
      if (error.message.includes('slippage')) throw error;

      // Wait before retry (exponential backoff)
      await new Promise(r => setTimeout(r, 1000 * attempt));
    }
  }

  throw lastError || new Error('Swap failed after retries');
}

模板 / 操作指南

前端兑换组件结构
// State management
interface SwapState {
  inputToken: Token | null;
  outputToken: Token | null;
  inputAmount: string;
  quote: QuoteResponse | null;
  loading: boolean;
  error: string | null;
  txStatus: 'idle' | 'signing' | 'confirming' | 'success' | 'failed';
}

// Component flow:
// 1. User selects tokens → fetch quote
// 2. User enters amount → debounced quote refresh
// 3. Display: output amount, price impact, route
// 4. User clicks swap → sign → send → confirm
// 5. Show success/failure with tx link

// Quote refresh interval: 10-15 seconds (balance freshness vs rate limits)
机器人兑换配置
interface BotSwapConfig {
  // Execution
  maxSlippageBps: number;
  minPriorityFeeMicroLamports: number;
  maxPriorityFeeMicroLamports: number;
  maxRetries: number;

  // Safety
  maxTradeSize: number; // In USD
  maxPriceImpact: number; // Percentage
  cooldownMs: number; // Between trades

  // Monitoring
  logAllQuotes: boolean;
  alertOnFailure: boolean;
}

const defaultBotConfig: BotSwapConfig = {
  maxSlippageBps: 100,
  minPriorityFeeMicroLamports: 1000,
  maxPriorityFeeMicroLamports: 100000,
  maxRetries: 3,
  maxTradeSize: 1000,
  maxPriceImpact: 3,
  cooldownMs: 1000,
  logAllQuotes: true,
  alertOnFailure: true,
};
价格影响阈值
function assessPriceImpact(impactPct: number): {
  level: 'low' | 'medium' | 'high' | 'extreme';
  warning: string | null;
} {
  if (impactPct < 0.5) return { level: 'low', warning: null };
  if (impactPct < 2) return { level: 'medium', warning: 'Moderate price impact' };
  if (impactPct < 5) return { level: 'high', warning: 'High price impact - consider smaller trade' };
  return { level: 'extreme', warning: 'Extreme price impact - trade size too large for liquidity' };
}

常见故障模式与调试

“交易模拟失败”
  • 原因:报价过期,价格变动超出滑点范围
  • 检测:错误消息包含“slippage”或“amount out”
  • 解决方法:提高滑点,或在执行前刷新报价
“交易已过期”
  • 原因:确认前区块哈希已过期(超过 60 秒)
  • 检测:错误消息包含“blockhash not found”
  • 解决方法:提高优先费;使用 skipPreflight: false
“SOL 不足以支付费用”
  • 原因:用户没有足够的 SOL 支付租金和优先费
  • 检测:兑换前检查余额
  • 解决方法:至少预留 0.01 SOL;向用户发出警告
“被 Jupiter 限流”
  • 原因:每分钟请求数超过 60 次
  • 检测:状态码为 429
  • 解决方法:实现请求排队;缓存报价;使用付费套餐
“未找到路径”
  • 原因:代币之间不存在流动性路径
  • 检测:报价响应中的路径列表为空
  • 解决方法:检查代币是否有流动性;尝试使用中间代币(SOL/USDC)
“交易过大”
  • 原因:路径复杂,包含多个跳转
  • 检测:错误提示包含交易大小相关信息
  • 解决方法:使用 onlyDirectRoutes: true 或增加计算预算

质量标准 / 验证

集成完成的标准:

  • 能够可靠地获取报价,并妥善处理错误
  • 根据代币类型正确设置滑点
  • 优先费会根据网络状况进行调整
  • 失败的交易会采用退避策略重试
  • 用户能清楚看到每一步的状态(加载、签名、确认)
  • 大额交易会显示价格影响警告
  • 能够妥善处理速率限制
  • 交易成功后会提供交易链接

输出格式

提供:

  1. 实现代码:包含适当类型和错误处理的 TypeScript
  2. 配置值:滑点、优先费用、超时时间
  3. 错误处理策略:哪些错误需要重试,哪些错误需要直接反馈
  4. 用户体验考量:加载状态、确认、警告
  5. 测试清单:部署前需要验证的场景

示例

简单示例:基本兑换函数

输入:“创建一个将 SOL 兑换为任意代币的函数”

输出:

import { Connection, PublicKey, VersionedTransaction } from '@solana/web3.js';

const JUPITER_API = 'https://quote-api.jup.ag/v6';
const SOL_MINT = 'So11111111111111111111111111111111111111112';

interface SwapSolParams {
  outputMint: string;
  amountLamports: number;
  slippageBps: number;
  userPublicKey: PublicKey;
  signTransaction: (tx: VersionedTransaction) => Promise<VersionedTransaction>;
  connection: Connection;
}

export async function swapSolToToken(params: SwapSolParams): Promise<string> {
  // 1. Get quote
  const quoteUrl = `${JUPITER_API}/quote?inputMint=${SOL_MINT}&outputMint=${params.outputMint}&amount=${params.amountLamports}&slippageBps=${params.slippageBps}`;

  const quoteResponse = await fetch(quoteUrl);
  if (!quoteResponse.ok) throw new Error('Failed to get quote');
  const quote = await quoteResponse.json();

  // 2. Get swap transaction
  const swapResponse = await fetch(`${JUPITER_API}/swap`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      quoteResponse: quote,
      userPublicKey: params.userPublicKey.toBase58(),
      wrapAndUnwrapSol: true,
      computeUnitPriceMicroLamports: 5000, // 0.000005 SOL priority
    }),
  });

  const { swapTransaction } = await swapResponse.json();

  // 3. Sign and send
  const tx = VersionedTransaction.deserialize(Buffer.from(swapTransaction, 'base64'));
  const signedTx = await params.signTransaction(tx);

  const signature = await params.connection.sendTransaction(signedTx);
  await params.connection.confirmTransaction(signature, 'confirmed');

  return signature;
}
复杂示例:生产级兑换服务

输入:“构建一个包含重试、速率限制和监控功能的兑换服务”

输出:

// See full implementation in examples/swap-service.ts
// Key features:
// - Request queue with rate limiting (60/min)
// - Exponential backoff on failures
// - Priority fee escalation on retries
// - Quote caching (10s TTL)
// - Prometheus metrics export
// - Structured logging
// - Health check endpoint

class JupiterSwapService {
  private requestQueue: RequestQueue;
  private quoteCache: LRUCache<string, Quote>;
  private metrics: SwapMetrics;

  async swap(params: SwapParams): Promise<SwapResult> {
    const startTime = Date.now();

    try {
      // Check rate limit
      await this.requestQueue.acquire();

      // Get or refresh quote
      const quote = await this.getQuoteWithCache(params);

      // Validate
      this.validateQuote(quote, params);

      // Execute with retries
      const signature = await this.executeWithRetry(quote, params);

      // Record success
      this.metrics.recordSwap('success', Date.now() - startTime);

      return { success: true, signature, quote };

    } catch (error) {
      this.metrics.recordSwap('failure', Date.now() - startTime);
      throw error;
    }
  }
}

评论

支持 Markdown