关于 jupiter-lend
Jupiter Lend 是 Solana 上的借贷协议集成技能,面向构建借贷应用和数据工具的开发者。它涵盖 Earn、Vaults 与流动性查询,并提供读写 SDK 的用法指导。
主要功能
- 01查询 jlToken 市场与用户仓位
- 02发现 Vault 配置和用户仓位
- 03构建抵押、借款及还款操作
- 04获取流动性利率和市场数据
- 05执行同一交易内的闪电贷
适用场景
- 01展示可用 Vault 和用户仓位
- 02构建抵押并同时借款的交易
- 03查询代币供应与借款利率
- 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
构建工具包文档索引
- 快速入门:概览、API 与 SDK
- 赚取收益:概览、存入、提取、读取数据
- 钱包集成(Privy):使用 Privy 赚取收益、使用 Privy 借款
- 借款:概览、创建头寸、存入、借款、还款、提取、组合操作、清算、读取金库数据
- 闪电贷:概览、执行
- 高级功能:advanced/multiply、advanced/unwind、advanced/repay-withdraw-collateral、advanced/vault-swap、advanced/utilization-after-deposit、advanced/native-staked-vault/overview、advanced/native-staked-vault/deposit、advanced/native-staked-vault/withdraw
- 流动性:liquidity/analytics
- 资源:resources/program-addresses、resources/idl-and-types、resources/dune
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 文档
- Jupiter Lend 概览:developers.jup.ag/docs/lend
- Lend API(赚取收益):api-reference/lend/earn | 用于赚取收益操作(存入/提取/铸造/赎回、代币、头寸、收益)的 REST API
- Lend API(借款):(即将推出)
SDK
- Read SDK (
@jup-ag/lend-read):NPM | 用于查询流动性池、借贷市场(jlTokens)和金库的只读 SDK - Write SDK (
@jup-ag/lend):NPM | 用于构建写入交易(存入、提取、操作)的核心 SDK
智能合约
- 公共代码库:Instadapp/fluid-solana-programs
- IDL 和类型:IDL 和类型(
/target文件夹)
程序 ID(主网)
| 程序 | 地址 |
|---|---|
| 流动性 | jupeiUmn818Jg1ekPURTpr4mFo29p46vygyykFJ3wZC |
| 借贷(Earn) | jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9 |
| 借贷奖励利率模型 | jup7TthsMgcR9Y3L277b8Eo9uboVSmu1utkuXHNUKar |
| 金库(借款) | jupr81YtYssSyPt8jbnGuiWon5f6x9TcDEFxYe3Bdzi |
| 预言机 | jupnw4B6Eqs7ft6rxpzYLJZYSnrpRgPcr589n5Kv4oc |
| 闪电贷 | jupgfSgfuAXv4B6R2Uxu85Z1qdzgju79s6MfZekN6XS |