mcpField
J
jupiter-lend

jupiter-lend

github.com/jup-ag其他85319 次安装16 周前更新
代码仓库

关于 jupiter-lend

Jupiter Lend 是 Solana 上的借贷协议集成技能,面向构建借贷应用和数据工具的开发者。它涵盖 Earn、Vaults 与流动性查询,并提供读写 SDK 的用法指导。

主要功能

  1. 01查询 jlToken 市场与用户仓位
  2. 02发现 Vault 配置和用户仓位
  3. 03构建抵押、借款及还款操作
  4. 04获取流动性利率和市场数据
  5. 05执行同一交易内的闪电贷

适用场景

  1. 01展示可用 Vault 和用户仓位
  2. 02构建抵押并同时借款的交易
  3. 03查询代币供应与借款利率
  4. 04为套利或清算构建闪电贷

安装

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

$npx skills add https://github.com/jup-ag/agent-skills --skill jupiter-lend

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

附带文件README.md

详细介绍

Jupiter Lend Protocol

Jupiter Lend(由 Fluid Protocol 提供支持)是 Solana 上的借贷协议,提供流动性池、借贷市场(jlTokens)和用于杠杆头寸的金库。

该协议使用两个主要 SDK:

  • @jup-ag/lend-read:适用于所有程序(Liquidity、Lending、Vaults)的只读查询
  • @jup-ag/lend:写入操作(存入、提取、借款、还款)

Agent 使用

以下是一些可用于演示 Jupiter Lend 集成的示例提示词:

  • 查找并列出所有可用金库
  • 获取某个用户的所有金库头寸
  • 在单笔交易中存入抵押品并借款
  • 偿还某个头寸的最大债务并提取最大抵押品
  • 获取用户的 Earn(jlToken)头寸及其底层资产余额
  • 为套利或清算构建闪电贷
  • 获取某个代币的流动性利率和 APY
  • 创建新的金库头寸(positionId 0),存入抵押品并借款

SDK 安装

# For read operations (queries, prices, positions)
npm install @jup-ag/lend-read

# For write operations (transactions)
npm install @jup-ag/lend

1. 核心概念与协议术语

了解 Jupiter Lend 的架构和术语,有助于构建更完善的集成。

架构:双层模型
  • 流动性层(单一订单簿):基础层,所有资产都存放于此。该层管理代币限额、利率曲线和统一流动性。用户不会直接与其交互。
  • 协议层:面向用户的模块(Lending 和 Vaults),构建在流动性层之上,并通过跨程序调用(CPI)与其交互。
术语
  • jlToken(Jupiter Lend 代币):向 Lending 协议供应代币时获得的生息资产(例如,jlUSDC)。随着利息累积,兑换率会提高,使你的 jlToken 可兑换更多底层 USDC。
  • 兑换价格:用于在存储的“原始”金额与实际代币金额之间进行换算的汇率。供应资产赚取利息或债务产生利息时,该汇率会持续提高。
  • 抵押系数(CF):开仓或管理头寸时允许的最大贷款价值比(LTV)。
  • 清算阈值(LT):头寸变为抵押不足并符合清算条件时对应的 LTV。
  • 清算上限(LML):绝对最大 LTV 限值。如果头寸的风险比率超过此限值,协议会自动吸收该头寸,以保护流动性提供者。
  • 清算罚金:清算人代高风险头寸偿还债务时获得的折扣比例。
  • 再平衡:将上层协议的会计记录(金库/Lending)与其在流动性层上的实际头寸同步的操作。此操作还会同步订单簿,以计入任何已累积的奖励。
  • 基于 Tick 的架构:Vaults 协议根据头寸的风险等级(债务与抵押品比率)将其分组到“tick”中。这使协议能够高效管理风险,并大规模处理清算。
  • 零头借款:有意在头寸中保留的少量剩余债务,用于处理除法舍入问题。
  • 哨兵值:MAX_WITHDRAW_AMOUNT 和 MAX_REPAY_AMOUNT 等常量,告知协议动态计算并提取/偿还某个头寸在数学上允许的最大金额。
金额和单位

所有 SDK 金额均使用基本单位(代币的最小单位,例如,6 位小数的代币中 1_000_000 = 1 USDC)。


2. Jupiter Earn(借贷)

Jupiter Earn 允许用户供应资产以赚取收益。作为回报,用户会获得生息的 jlTokens(例如,jlUSDC)。

借贷模块(jlTokens)

访问 jlToken(Jupiter Lend 代币)市场、兑换价格和用户头寸。

// Get all jlToken details at once
const allDetails = await client.lending.getAllJlTokenDetails();

// Get user's jlToken balance
const position = await client.lending.getUserPosition(USDC, userPublicKey);

借贷(Earn)

存入底层资产以获取生息代币,或提取这些代币。

import { getDepositIxs, getWithdrawIxs } from "@jup-ag/lend/earn";
import BN from "bn.js";

// Deposit 1 USDC (base units: 1_000_000 for 6 decimals)
const { ixs: depositIxs } = await getDepositIxs({
  amount: new BN(1_000_000),
  asset: USDC_PUBKEY,
  signer: userPublicKey,
  connection,
});

// Withdraw 0.1 USDC (100_000 base units @ 6 decimals)
const { ixs: withdrawIxs } = await getWithdrawIxs({
  amount: new BN(100_000),
  asset: USDC_PUBKEY,
  signer: userPublicKey,
  connection,
});

3. Jupiter Borrow(Vaults)

金库用于存入抵押品并借入债务。

金库模块与发现

访问金库配置、持仓、交易所价格和清算数据。这对于动态列出所有可用的杠杆市场至关重要。

// Discover all available vaults
const allVaults = await client.vault.getAllVaults();
const totalVaults = allVaults.length;

// Get comprehensive vault data (config + state + rates + limits) for a specific vault
const vaultId = 1;
const vaultData = await client.vault.getVaultByVaultId(vaultId);

// Check borrowing limits dynamically before prompting users
const borrowLimit = vaultData.limitsAndAvailability.borrowLimit;
const borrowable = vaultData.limitsAndAvailability.borrowable;

查找用户的金库持仓

在执行金库操作(例如存入、借款或还款)之前,需要知道用户现有的 positionId(它对应一个 NFT)。

const userPublicKey = new PublicKey("YOUR_WALLET_PUBKEY");

// Retrieve all positions owned by the user
// Each position includes full vault data: NftPosition & { vault: VaultEntireData }
const positions = await client.vault.getAllUserPositions(userPublicKey);

positions.forEach((p) => {
  console.log(`Position ID (nftId): ${p.nftId}`);
  console.log(`Vault ID: ${p.vault.constantViews.vaultId}`);
  console.log(`Collateral Supplied: ${p.supply.toString()}`);
  console.log(`Debt Borrowed: ${p.borrow.toString()}`);
});

金库(借款)

金库用于管理抵押品存入和债务借款。所有金库操作都使用 getOperateIx 函数。

操作方向由 colAmount 和 debtAmount 的正负决定:

  • 存入:colAmount > 0,debtAmount = 0
  • 取出:colAmount < 0,debtAmount = 0
  • 借款:colAmount = 0,debtAmount > 0
  • 还款:colAmount = 0,debtAmount < 0

特殊值:MAX_REPAY_AMOUNT 和 MAX_WITHDRAW_AMOUNT 已带负号;请直接传入,不要对它们调用 .neg()。

重要提示:如果 positionId 为 0,系统会创建新的持仓 NFT,SDK 会返回新的 positionId。

常见金库操作模式

1. 存入抵押品

import { getOperateIx } from "@jup-ag/lend/borrow";

// Deposit 1 USDC (base units: 1_000_000 for 6 decimals)
const { ixs, addressLookupTableAccounts, positionId: newPositionId } = await getOperateIx({
  vaultId: 1,
  positionId: 0, // 0 = create new position
  colAmount: new BN(1_000_000), // Positive = Deposit
  debtAmount: new BN(0),
  connection,
  signer,
});

2. 借入债务

// Borrow 0.5 USDC (500_000 base units @ 6 decimals)
const { ixs, addressLookupTableAccounts } = await getOperateIx({
  vaultId: 1,
  positionId: EXISTING_POSITION_ID, // Use the nftId retrieved from the read SDK
  colAmount: new BN(0),
  debtAmount: new BN(500_000), // Positive = Borrow (0.5 USDC @ 6 decimals)
  connection,
  signer,
});

3. 还款(使用最大值特殊值) 用户想要偿还全部债务时,不要尝试计算精确的微小余额金额。请使用 SDK 导出的 MAX_REPAY_AMOUNT 特殊值。

import { getOperateIx, MAX_REPAY_AMOUNT } from "@jup-ag/lend/borrow";

const { ixs, addressLookupTableAccounts } = await getOperateIx({
  vaultId: 1,
  positionId: EXISTING_POSITION_ID,
  colAmount: new BN(0),
  debtAmount: MAX_REPAY_AMOUNT, // Tells the protocol to clear the full debt
  connection,
  signer,
});

4. 取出抵押品(使用最大值特殊值) 同样,要取出所有可用抵押品,请使用 MAX_WITHDRAW_AMOUNT 特殊值。

import { getOperateIx, MAX_WITHDRAW_AMOUNT } from "@jup-ag/lend/borrow";

const { ixs, addressLookupTableAccounts } = await getOperateIx({
  vaultId: 1,
  positionId: EXISTING_POSITION_ID,
  colAmount: MAX_WITHDRAW_AMOUNT, // Tells the protocol to withdraw everything
  debtAmount: new BN(0),
  connection,
  signer,
});

5. 组合操作

你可以使用 getOperateIx 在单笔交易中批量执行多个操作,例如存入 + 借款,或还款 + 取出:

  • a. 在一笔 Tx 中存入 + 借款: 同时传入 colAmount 和 debtAmount,即可存入抵押品并借款。
    const { ixs, addressLookupTableAccounts } = await getOperateIx({
      vaultId: 1,
      positionId: 0, // Create new position
      colAmount: new BN(1_000_000), // Deposit 1 USDC (6 decimals)
      debtAmount: new BN(500_000),  // Borrow 0.5 USDC (6 decimals)
      connection,
      signer,
    });
    
  • b. 在一笔 Tx 中还款 + 取出: 一次性还款并取出抵押品。全额还款或取出最大可用金额时,请使用最大值特殊值。
    import { getOperateIx, MAX_WITHDRAW_AMOUNT, MAX_REPAY_AMOUNT } from "@jup-ag/lend/borrow";
    
    const { ixs, addressLookupTableAccounts } = await getOperateIx({
      vaultId: 1,
      positionId: EXISTING_POSITION_ID,
      colAmount: MAX_WITHDRAW_AMOUNT, // Withdraw all collateral
      debtAmount: MAX_REPAY_AMOUNT,   // Repay all debt
      connection,
      signer,
    });
    


4. 闪电贷

闪电贷允许你从协议中借入流动性,无需预先提供抵押品。必须在完全相同的一笔交易中归还借入的金额,且不收取闪电贷费用。你可以直接借入所需资产,用于套利、清算或其他场景。

执行闪电贷(@jup-ag/lend)

@jup-ag/lend SDK 提供了简单的辅助函数,用于获取执行闪电贷所需的指令。最便捷的方式是使用 getFlashloanIx。

import { getFlashloanIx } from "@jup-ag/lend/flashloan";
import { Connection, PublicKey, TransactionMessage, VersionedTransaction } from "@solana/web3.js";
import BN from "bn.js";

async function executeFlashloan() {
  const connection = new Connection("https://api.mainnet-beta.solana.com");
  const signer = new PublicKey("YOUR_WALLET_PUBKEY");
  const asset = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); // USDC

  const borrowAmount = new BN(100_000_000); // 100 USDC (base units, 6 decimals)

  // 1. Get the borrow and payback instructions
  const { borrowIx, paybackIx } = await getFlashloanIx({
    connection,
    signer,
    asset,
    amount: borrowAmount,
  });

  // 2. Define your custom instructions that utilize the borrowed funds
  const myCustomArbitrageInstructions = [
    // ... your instructions here
  ];

  // 3. Assemble the transaction: Borrow -> Custom Logic -> Payback
  const instructions = [
    borrowIx,
    ...myCustomArbitrageInstructions,
    paybackIx
  ];

  const latestBlockhash = await connection.getLatestBlockhash();
  const message = new TransactionMessage({
    payerKey: signer,
    recentBlockhash: latestBlockhash.blockhash,
    instructions,
  }).compileToV0Message();

  const transaction = new VersionedTransaction(message);
  // Sign and send...
}

5. 流动性

流动性层是 Jupiter Lend 的基础,持有所有底层资产。虽然你通常会与 Earn 和 Borrow 层交互,但直接查询流动性层对于分析、仪表板和 APY 聚合器非常有用。

流动性模块

访问流动性池数据、利率以及用户的供应/借款持仓。

const USDC = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");

// Get market data for a token (rates, prices, utilization)
const data = await client.liquidity.getOverallTokenData(USDC);

// View rates (basis points: 10000 = 100%)
const supplyApr = Number(data.supplyRate) / 100;
const borrowApr = Number(data.borrowRate) / 100;

6. Jupiter Lend 构建套件

Jupiter Lend 构建套件提供开发者组件、强大的实用工具和深入的文档,帮助你高效构建并集成 Jupiter Lend。

基础 URL:https://developers.jup.ag/docs/lend

构建工具包文档索引

7. 完整可运行示例

可直接复制粘贴的脚本。安装依赖:npm install @solana/web3.js bn.js @jup-ag/lend @jup-ag/lend-read

示例 1 — 查找头寸并存入(先读取,再写入)

此示例演示如何使用只读 SDK(@jup-ag/lend-read)查询用户现有的金库头寸。如果目标金库存在头寸,则使用该 NFT ID;如果不存在,则创建新头寸。最后,使用写入 SDK(@jup-ag/lend)向该头寸存入抵押品。

import {
  Connection,
  Keypair,
  PublicKey,
  TransactionMessage,
  VersionedTransaction,
} from "@solana/web3.js";
import BN from "bn.js";
import { Client } from "@jup-ag/lend-read";
import { getOperateIx } from "@jup-ag/lend/borrow";
import fs from "fs";
import path from "path";

const KEYPAIR_PATH = "/path/to/your/keypair.json";
const RPC_URL = "https://api.mainnet-beta.solana.com";
const VAULT_ID = 1;

const DEPOSIT_AMOUNT = new BN(1_000_000); // 1 USDC @ 6 decimals

function loadKeypair(keypairPath: string): Keypair {
  const fullPath = path.resolve(keypairPath);
  const secret = JSON.parse(fs.readFileSync(fullPath, "utf8"));
  return Keypair.fromSecretKey(new Uint8Array(secret));
}

async function main() {
  const userKeypair = loadKeypair(KEYPAIR_PATH);
  const connection = new Connection(RPC_URL, { commitment: "confirmed" });
  const signer = userKeypair.publicKey;

  // 1. Read Data: Find existing user positions for the vault
  const client = new Client(connection);
  const positions = await client.vault.getAllUserPositions(signer);

  let targetPositionId = 0; // 0 = create new position

  const existing = positions.find((p) => p.vault.constantViews.vaultId === VAULT_ID);
  if (existing) {
    targetPositionId = existing.nftId;
    console.log(`Found existing position NFT: ${targetPositionId}`);
  }

  if (targetPositionId === 0) {
    console.log("No existing position found. Will create a new one.");
  }

  // 2. Write Data: Execute deposit
  const { ixs, addressLookupTableAccounts, nftId } = await getOperateIx({
    vaultId: VAULT_ID,
    positionId: targetPositionId,
    colAmount: DEPOSIT_AMOUNT,
    debtAmount: new BN(0), // Deposit only
    connection,
    signer,
  });

  if (!ixs?.length) throw new Error("No instructions returned.");

  // 3. Build the V0 Transaction Message
  const latestBlockhash = await connection.getLatestBlockhash();
  const message = new TransactionMessage({
    payerKey: signer,
    recentBlockhash: latestBlockhash.blockhash,
    instructions: ixs,
  }).compileToV0Message(addressLookupTableAccounts ?? []);

  // 4. Sign and Send
  const transaction = new VersionedTransaction(message);
  transaction.sign([userKeypair]);

  const signature = await connection.sendTransaction(transaction, {
    skipPreflight: false,
    maxRetries: 3,
    preflightCommitment: "confirmed",
  });

  await connection.confirmTransaction({ signature, ...latestBlockhash }, "confirmed");

  console.log(`Deposit successful! Signature: ${signature}`);
  if (targetPositionId === 0) {
    console.log(`New position created with NFT ID: ${nftId}`);
  }
}

main().catch(console.error);

示例 2 — 组合操作(存入、借款、还款、提取)

此示例演示如何在单笔交易中创建头寸、存入抵押品并借入债务。随后,在后续交易中使用完全相同的 getOperateIx 函数偿还债务并提取抵押品。示例还展示了合并多组指令时对地址查找表(ALT)去重这一关键步骤。

import {
  Connection,
  Keypair,
  TransactionMessage,
  VersionedTransaction,
} from "@solana/web3.js";
import BN from "bn.js";
import { getOperateIx } from "@jup-ag/lend/borrow";
import fs from "fs";
import path from "path";

const KEYPAIR_PATH = "/path/to/your/keypair.json";
const RPC_URL = "https://api.mainnet-beta.solana.com";
const VAULT_ID = 1;

const DEPOSIT_AMOUNT = new BN(1_000_000);  // 1 USDC @ 6 decimals
const BORROW_AMOUNT = new BN(500_000);    // 0.5 USDC @ 6 decimals
const REPAY_AMOUNT = new BN(100_000);     // 0.1 USDC @ 6 decimals
const WITHDRAW_AMOUNT = new BN(200_000);  // 0.2 USDC @ 6 decimals

function loadKeypair(keypairPath: string): Keypair {
  const fullPath = path.resolve(keypairPath);
  const secret = JSON.parse(fs.readFileSync(fullPath, "utf8"));
  return Keypair.fromSecretKey(new Uint8Array(secret));
}

async function main() {
  const userKeypair = loadKeypair(KEYPAIR_PATH);
  const connection = new Connection(RPC_URL, { commitment: "confirmed" });
  const signer = userKeypair.publicKey;

  // 1. Create position + Deposit + Borrow
  const { ixs: depositBorrowIxs, addressLookupTableAccounts: depositBorrowAlts, positionId } = await getOperateIx({
    vaultId: VAULT_ID,
    positionId: 0,
    colAmount: DEPOSIT_AMOUNT,
    debtAmount: BORROW_AMOUNT,
    connection,
    signer,
  });

  // 2. Repay + Withdraw
  const repayWithdrawResult = await getOperateIx({
    vaultId: VAULT_ID,
    positionId: positionId!,
    colAmount: WITHDRAW_AMOUNT.neg(),
    debtAmount: REPAY_AMOUNT.neg(),
    connection,
    signer,
  });

  // Merge instructions
  const allIxs = [...(depositBorrowIxs ?? []), ...(repayWithdrawResult.ixs ?? [])];

  // Merge and Deduplicate Address Lookup Tables (ALTs)
  const allAlts = [
    ...(depositBorrowAlts ?? []),
    ...(repayWithdrawResult.addressLookupTableAccounts ?? []),
  ];
  const seenKeys = new Set<string>();
  const mergedAlts = allAlts.filter((alt) => {
    const k = alt.key.toString();
    if (seenKeys.has(k)) return false;
    seenKeys.add(k);
    return true;
  });

  if (!allIxs.length) throw new Error("No instructions returned.");

  // Build the V0 Transaction Message
  const latestBlockhash = await connection.getLatestBlockhash();
  const message = new TransactionMessage({
    payerKey: signer,
    recentBlockhash: latestBlockhash.blockhash,
    instructions: allIxs,
  }).compileToV0Message(mergedAlts);

  // Sign and Send
  const transaction = new VersionedTransaction(message);
  transaction.sign([userKeypair]);

  const signature = await connection.sendTransaction(transaction, {
    skipPreflight: false,
    maxRetries: 3,
    preflightCommitment: "confirmed",
  });

  await connection.confirmTransaction({ signature, ...latestBlockhash }, "confirmed");

  console.log("Combined operate successful! Signature:", signature);
}

main().catch(console.error);

8. 资源

API 文档

SDK

  • Read SDK (@jup-ag/lend-read):NPM | 用于查询流动性池、借贷市场(jlTokens)和金库的只读 SDK
  • Write SDK (@jup-ag/lend):NPM | 用于构建写入交易(存入、提取、操作)的核心 SDK

智能合约

程序 ID(主网)

程序地址
流动性jupeiUmn818Jg1ekPURTpr4mFo29p46vygyykFJ3wZC
借贷(Earn)jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9
借贷奖励利率模型jup7TthsMgcR9Y3L277b8Eo9uboVSmu1utkuXHNUKar
金库(借款)jupr81YtYssSyPt8jbnGuiWon5f6x9TcDEFxYe3Bdzi
预言机jupnw4B6Eqs7ft6rxpzYLJZYSnrpRgPcr589n5Kv4oc
闪电贷jupgfSgfuAXv4B6R2Uxu85Z1qdzgju79s6MfZekN6XS

评论

支持 Markdown