跳转到主要内容

概述

Metis 是 Jupiter 的低级别 Swap 路由引擎。它对 Swap 交易的每个环节都提供精细控制:路由选择、指令组合、优先费用、计算单元限制、滑点和广播方式。与 Jupiter Ultra 不同,Metis 需要你自行处理这些内容——但作为回报,你获得了对需要 CPI、自定义指令或特定交易广播策略的集成的最大灵活性。 适合使用 Metis 的场景:
  • 与你自己的链上程序进行 CPI(跨程序调用)
  • 在 Swap 前后组合自定义指令
  • 完全控制优先费用、计算单元和滑点
  • 使用自定义 RPC 或 Jito 广播
建议使用 Ultra 的场景:
  • 无需管理滑点、费用或广播,只需端到端执行
  • 需要实时滑点估算器(RTSE),仅通过 Ultra 提供
Metis Swap API 通过 OrbitFlare 专用节点/jup 路径前缀访问。如需使用 Jupiter 托管的 API,请使用 https://api.jup.ag/swap/v1/... 并携带你的 x-api-key

工作原理

1

获取报价

使用输入代币地址、输出代币地址、数量和滑点调用 GET /swap/v1/quote,从 Metis 路由引擎获取最优路径。
2

构建 Swap 交易

将报价响应 POST 到 POST /swap/v1/swap。API 返回可签名的序列化 base64 交易,支持优先费用估算、动态计算单元限制和动态滑点。
3

签名并发送

反序列化 base64 交易,用你的钱包签名,然后通过 connection.sendRawTransaction() 或 Jito 广播。

第一步——获取报价

端点: GET /swap/v1/quote

必需参数

参数说明
inputMint输入代币的 mint 地址(例如 SOL 为 So11111111111111111111111111111111111111112
outputMint输出代币的 mint 地址(例如 USDC 为 EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
amount输入代币的原始整数数量(SOL 为 lamports,其他代币为最小单位)
slippageBps最大滑点容忍度,单位为基点(例如 50 = 0.5%)

示例——获取 1 SOL 兑换 USDC 的报价

const quoteResponse = await (
  await fetch(
    "https://api.jup.ag/swap/v1/quote?" +
      "inputMint=So11111111111111111111111111111111111111112" +
      "&outputMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" +
      "&amount=100000000" +
      "&slippageBps=50" +
      "&restrictIntermediateTokens=true",
    {
      headers: {
        "x-api-key": "YOUR_API_KEY",
      },
    }
  )
).json();

console.log(JSON.stringify(quoteResponse, null, 2));

示例响应

{
  "inputMint": "So11111111111111111111111111111111111111112",
  "inAmount": "100000000",
  "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "outAmount": "16198753",
  "otherAmountThreshold": "16117760",
  "swapMode": "ExactIn",
  "slippageBps": 50,
  "platformFee": null,
  "priceImpactPct": "0",
  "routePlan": [
    {
      "swapInfo": {
        "ammKey": "5BKxfWMbmYBAEWvyPZS9esPducUba9GqyMjtLCfbaqyF",
        "label": "Meteora DLMM",
        "inputMint": "So11111111111111111111111111111111111111112",
        "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
        "inAmount": "100000000",
        "outAmount": "16198753"
      },
      "percent": 100
    }
  ],
  "contextSlot": 299283763,
  "timeTaken": 0.015257836
}
outAmount 是报价时的最佳输出数量。slippageBps 不影响此值——它控制 otherAmountThreshold,即你可以接受的最低输出数量。

其他报价选项

设置为 true 可确保路由仅通过高流动性的中间代币。这能减少因流动性差的路径导致的路由失败,提高路由稳定性,但可能略微影响价格。
设置为 true 可限制路由仅通过单个市场(无多跳)。如果不存在直接路由则不返回报价。可能导致不利价格,请谨慎使用。
限制内部 Swap 指令中的账户总数。当你需要为自定义指令留出空间时很有用。推荐最小值为 64。设置过低会导致路由中移除需要更多账户的 DEX(例如 Meteora DLMM 最多需要 47 个账户)。
向 Swap 添加费用,计入你的 feeAccount。需配合 Swap 请求中的 feeAccount 参数使用。

第二步——构建 Swap 交易

端点: POST /swap/v1/swap 将第一步的报价响应与用户公钥一起传入。API 返回已序列化的 base64 交易,可直接签名并发送。

构建带交易上链优化的 Swap 交易

const swapResponse = await (
  await fetch("https://api.jup.ag/swap/v1/swap", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      quoteResponse,
      userPublicKey: wallet.publicKey.toString(),

      // 优化交易上链
      dynamicComputeUnitLimit: true,
      dynamicSlippage: true,
      prioritizationFeeLamports: {
        priorityLevelWithMaxLamports: {
          maxLamports: 1000000,
          priorityLevel: "veryHigh",
        },
      },
    }),
  })
).json();

示例响应

{
  "swapTransaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAGDkS+...",
  "lastValidBlockHeight": 279632475,
  "prioritizationFeeLamports": 9999,
  "computeUnitLimit": 388876,
  "prioritizationType": {
    "computeBudget": {
      "microLamports": 25715,
      "estimatedMicroLamports": 785154
    }
  },
  "dynamicSlippageReport": {
    "slippageBps": 50,
    "otherAmount": 20612318,
    "simulatedIncurredSlippageBps": -18,
    "amplificationRatio": "1.5",
    "categoryName": "lst",
    "heuristicMaxSlippageBps": 100
  },
  "simulationError": null
}

优先费用级别

priorityLevel百分位数适用场景
medium第 25 百分位低拥堵、非时间敏感
high第 50 百分位标准交易条件
veryHigh第 75 百分位竞争激烈、MEV、时间敏感型 Swap
设置 maxLamports 作为安全上限以防止在费用飙升时多付:
prioritizationFeeLamports: {
  priorityLevelWithMaxLamports: {
    maxLamports: 10000000,
    global: false,      // 使用本地费用市场(可写账户),而非全局市场
    priorityLevel: "veryHigh",
  },
}

使用 Swap Instructions 接口

如果你需要将 Swap 与自定义指令组合,可使用 /swap/v1/swap-instructions 代替 /swap/v1/swap。它接受相同的参数,但返回单独的指令对象而非序列化交易:
const instructions = await (
  await fetch("https://api.jup.ag/swap/v1/swap-instructions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      quoteResponse,
      userPublicKey: wallet.publicKey.toString(),
    }),
  })
).json();

const {
  computeBudgetInstructions,
  setupInstructions,
  swapInstruction: swapInstructionPayload,
  cleanupInstruction,
  addressLookupTableAddresses,
} = instructions;

第三步——发送 Swap 交易

反序列化、签名并序列化

响应中的 swapTransaction 字段是 base64 编码的。将其反序列化为 VersionedTransaction,签名后再转为二进制格式发送:
import { VersionedTransaction } from "@solana/web3.js";

const transactionBase64 = swapResponse.swapTransaction;
const transaction = VersionedTransaction.deserialize(
  Buffer.from(transactionBase64, "base64")
);

transaction.sign([wallet]);

const transactionBinary = transaction.serialize();

发送交易

const signature = await connection.sendRawTransaction(transactionBinary, {
  maxRetries: 2,
  skipPreflight: true,
});
选项说明
maxRetries放弃前的最大重试次数。如果省略,RPC 会一直重试到 blockhash 过期。
skipPreflight跳过提交前的签名验证和模拟。对速度敏感的 Swap 建议设置为 true

确认交易

const confirmation = await connection.confirmTransaction(
  { signature },
  "finalized"
);

if (confirmation.value.err) {
  throw new Error(
    `交易失败:${JSON.stringify(confirmation.value.err)}\nhttps://solscan.io/tx/${signature}/`
  );
} else {
  console.log(`交易成功:https://solscan.io/tx/${signature}/`);
}

通过 Jito 广播

要使用 Jito 获得更快的上链速度和 MEV 保护,将 prioritizationFeeLamports 替换为 Jito 小费并提交到 Jito RPC 端点:
body: JSON.stringify({
  quoteResponse,
  userPublicKey: wallet.publicKey.toString(),
  prioritizationFeeLamports: {
    jitoTipLamports: 1000000, // 固定 lamports,不是上限
  },
}),
Jito 小费必须提交到 Jito RPC 端点才能生效。提交到普通 RPC 不会通过 Jito 的区块引擎路由。

高级功能

在 Swap 请求中启用 dynamicSlippage: true。后端会模拟交易,并根据代币类别应用启发式算法来估算合适的滑点值。注意:动态滑点的开发已停止。对于生产用途,Jupiter 建议使用包含实时滑点估算器(RTSE)的 Ultra Swap API——这是一个更准确、响应更快的系统。
自 2025 年 1 月起,建议通过 CPI 进行链上程序集成。在你的程序中添加 jupiter-cpi crate:
[dependencies]
jupiter-cpi = { git = "https://github.com/jup-ag/jupiter-cpi", rev = "5eb8977" }
然后从你的指令处理器调用共享账户路由。完整参考实现请参见 Jupiter CPI 示例
Flash Fill 是早期针对 CPI 账户大小限制的解决方案,使用版本化交易和地址查找表。自 Solana 主网部署 Loosen CPI 限制后,不再推荐使用。历史参考请见 sol-swap-flash-fill
使用 maxAccounts 时,各 DEX 的估计账户数如下(有 ALT 时取最小值,无 ALT 时取最大值):
DEX最大账户数最小账户数
Meteora DLMM4719
Meteora4518
Raydium4518
Raydium CLMM4519
Moonshot3715
Raydium CPMM3714
Pumpfun AMM4217
Pumpfun Bonding Curve4016
Orca Whirlpool3012
Obric3012
Solfi229
Sanctum8080
Sanctum Infinity8080
maxAccounts 设置过低会静默地将 DEX 从路由中排除。请尽量保持较高值,仅在交易超过 1232 字节大小限制时才降低。

要求与资源

通过 OrbitFlare 访问 Metis Swap API 仅适用于专用节点。API 可通过专用节点端点的 /jup 路径访问,或直接使用 https://api.jup.ag/swap/v1/... 并携带 Jupiter API key。