关于 lulo
lulo 是面向 Solana 应用开发者的 DeFi 储蓄平台集成指南,提供 API 和示例以构建存取款及账户查询功能。它支持自动收益分配、风险保护和自定义协议配置。
主要功能
- 01跨协议自动分配存款以获取收益
- 02Protected、Boosted 和自定义存款
- 03生成存款与取款交易
- 04查询账户余额、收益和 APY
- 05查看资金池利率与流动性
适用场景
- 01在 Solana 应用中集成存款与取款
- 02查看用户持仓及利息数据
- 03比较资金池 APY 与容量
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ sendaifun/ skills --skill lulo安装后在 Claude Code 中输入/lulo确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
docs/troubleshooting.mdexamples/balance/balance.tsexamples/deposit/deposit.tsexamples/integration/full-integration.tsexamples/withdraw/withdraw.tsresources/api-reference.mdtoken-addresses.mdtemplates/lulo-client.ts详细介绍
Lulo 开发指南
关于如何将 Lulo(Solana 上唯一的借贷聚合器)集成到应用中的全面指南。Lulo 会自动将存款路由到收益率最高的 DeFi 协议,并提供可选的智能合约保护。
什么是 Lulo?
Lulo(前身为 FlexLend)是 Solana 上面向稳定币的 DeFi 储蓄平台。它会自动将存款分配到集成的协议中,以最大化收益,同时维持所需的风险敞口。
主要功能
| 功能 | 描述 |
|---|---|
| 收益聚合 | 自动将存款路由到收益率最高的协议 |
| Lulo Protect | 内置智能合约风险保护(受保护 / 增益存款) |
| 自定义存款 | 全面控制协议分配和风险参数 |
| 即时提现 | 无锁定期(增益存款除外,其设有 48 小时冷却期) |
| 多协议 | 集成 Kamino、Drift、MarginFi、Jupiter |
| 无托管 | 资金直接流向集成的协议,而非由 Lulo 持有 |
为什么使用 Lulo?
- 自动再平衡:每小时检查利率,并自动将资金转移到收益更高的地方
- 风险管理:可选择受保护(有保险)、增益(更高收益)或自定义存款
- 零管理费:仅收取一次性初始化费用 0.005 SOL
- 多重奖励累积:单笔存款即可赚取多个协议的奖励
- 终身存款人数超过 9,400 人,定向流动性超过 3,400 万美元
概述
Lulo 提供三种存款类型:
- 受保护存款:收益稳定,并自动获得针对协议故障的保障
- 增益存款:为受保护存款提供保险,从而获得更高收益
- 自定义存款:直接控制哪些协议会收到你的资金
集成的协议
| 协议 | 描述 |
|---|---|
| Kamino Finance | 借贷和流动性金库 |
| Drift Protocol | 永续合约和借贷 |
| MarginFi | 借贷 |
| Jupiter | 借贷 / 赚取收益功能 |
支持的代币
- 稳定币:USDC、USDT、USDS、PYUSD
- 原生代币:SOL
- LST:bSOL、JitoSOL、mSOL
- 其他:BONK、JUP、ORCA、COPE、CASH
最低存款额:稳定币为 100 美元,原生代币为 1 SOL
快速开始
API 身份验证
所有 API 请求都需要有效的 API 密钥。请从 Lulo Developer Dashboard 获取密钥。
const headers = {
'Content-Type': 'application/json',
'x-api-key': process.env.LULO_API_KEY,
};
基础 URL
| 环境 | URL |
|---|---|
| 生产环境 | https://api.lulo.fi |
| Blinks | https://blink.lulo.fi |
| 开发者门户 | https://dev.lulo.fi |
API 参考
生成存款交易
创建用于将代币存入 Lulo 的序列化交易。
端点:POST /v1/generate.transactions.deposit
查询参数:
| 参数 | 类型 | 描述 |
|---|---|---|
priorityFee | number | 以 microlamports 为单位的优先费用(例如,500000) |
请求正文:
{
"owner": "YourWalletPublicKey",
"mintAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"depositType": "protected",
"amount": 100000000
}
响应:
{
"transaction": "base64EncodedSerializedTransaction",
"lastValidBlockHeight": 123456789
}
生成提现交易
创建用于从 Lulo 提取代币的序列化交易。
端点:POST /v1/generate.transactions.withdraw
查询参数:
| 参数 | 类型 | 描述 |
|---|---|---|
priorityFee | number | 以 microlamports 为单位的优先费用 |
请求正文:
{
"owner": "YourWalletPublicKey",
"mintAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"withdrawType": "protected",
"amount": 50000000
}
获取账户数据
获取用户余额、已赚取的利息和 APY 指标。
端点:GET /v1/account/{walletAddress}
响应:
{
"totalDeposited": 1000000000,
"totalInterestEarned": 5000000,
"currentApy": 8.5,
"positions": [
{
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"depositType": "protected",
"balance": 500000000,
"interestEarned": 2500000,
"apy": 7.2
}
]
}
获取资金池数据
返回当前 APY、流动性金额和容量指标。
端点:GET /v1/pools
响应:
{
"pools": [
{
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"symbol": "USDC",
"protectedApy": 6.5,
"boostedApy": 9.2,
"totalDeposited": 34000000000000,
"availableCapacity": 10000000000000
}
]
}
获取待处理的提现
列出包含冷却期的有效提现请求。
端点:GET /v1/account/{walletAddress}/pending-withdrawals
初始化推荐人
设置推荐人账户以赚取推荐费用。
端点:POST /v1/referrer/initialize
领取推荐奖励
处理推荐费领取。
端点:POST /v1/referrer/claim
存款类型说明
受保护存款
专为寻求稳定收益并希望获得自动保障的风险厌恶型用户设计。
运作方式:
- 存款通过集成协议中的借贷赚取利息
- 部分利息分配给增强型存款用户(保障费用)
- 如果某个协议发生故障,增强型存款会自动弥补受保护存款的损失
优势:
- 风险较低,享有优先保障
- 收益稳定且可预测
- 无需提交索赔,保障会自动生效
- 可即时提款
保障范围:智能合约漏洞利用、预言机故障、坏账事件
不在保障范围内:Solana 网络故障、USDC 脱锚、Lulo 合约故障
增强型存款
为受保护存款用户提供保险保障,以换取更高收益。
运作方式:
- 通过集成协议赚取借贷收益
- 通过受保护存款的利息分成获得额外收益
- 在协议发生故障时充当第一损失层
优势:
- APY 更高(通常比受保护存款高 1-2%)
- 双重收入来源(借贷收益 + 保障费用)
风险:
- 协议发生故障时处于第一损失位置
- 提款有 48 小时冷却期
自定义存款
全面掌控协议分配和风险参数。
功能:
- 选择特定协议(Kamino、Drift、MarginFi、Jupiter)
- 为每个协议设置最大敞口上限
- 收益变化时自动重新分配
- 不提供保障(直接承担协议敞口)
示例:如果将最大敞口设为 50%,并选择 3 个协议,则任何单个协议中都不会存入超过一半的资金。
集成示例
TypeScript:存入 Lulo
import { Connection, Transaction, VersionedTransaction, Keypair } from '@solana/web3.js';
const LULO_API_URL = 'https://api.lulo.fi';
interface DepositParams {
owner: string;
mintAddress: string;
amount: number;
depositType: 'protected' | 'boosted' | 'regular';
priorityFee?: number;
}
async function generateDepositTransaction(params: DepositParams): Promise<string> {
const { owner, mintAddress, amount, depositType, priorityFee = 500000 } = params;
const response = await fetch(
`${LULO_API_URL}/v1/generate.transactions.deposit?priorityFee=${priorityFee}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.LULO_API_KEY!,
},
body: JSON.stringify({
owner,
mintAddress,
depositType,
amount,
}),
}
);
if (!response.ok) {
throw new Error(`Deposit failed: ${response.statusText}`);
}
const data = await response.json();
return data.transaction;
}
async function deposit(
connection: Connection,
wallet: Keypair,
mintAddress: string,
amount: number,
depositType: 'protected' | 'boosted' | 'regular' = 'protected'
): Promise<string> {
// Generate deposit transaction
const serializedTx = await generateDepositTransaction({
owner: wallet.publicKey.toBase58(),
mintAddress,
amount,
depositType,
});
// Deserialize and sign
const txBuffer = Buffer.from(serializedTx, 'base64');
const transaction = VersionedTransaction.deserialize(txBuffer);
transaction.sign([wallet]);
// Send and confirm
const signature = await connection.sendTransaction(transaction);
await connection.confirmTransaction(signature, 'confirmed');
console.log('Deposit successful:', signature);
return signature;
}
// Usage
const connection = new Connection('https://api.mainnet-beta.solana.com');
const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
await deposit(
connection,
wallet,
USDC_MINT,
100_000_000, // 100 USDC (6 decimals)
'protected'
);
TypeScript:从 Lulo 提款
interface WithdrawParams {
owner: string;
mintAddress: string;
amount: number;
withdrawType: 'protected' | 'boosted' | 'regular';
priorityFee?: number;
}
async function generateWithdrawTransaction(params: WithdrawParams): Promise<string> {
const { owner, mintAddress, amount, withdrawType, priorityFee = 500000 } = params;
const response = await fetch(
`${LULO_API_URL}/v1/generate.transactions.withdraw?priorityFee=${priorityFee}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.LULO_API_KEY!,
},
body: JSON.stringify({
owner,
mintAddress,
withdrawType,
amount,
}),
}
);
if (!response.ok) {
throw new Error(`Withdrawal failed: ${response.statusText}`);
}
const data = await response.json();
return data.transaction;
}
async function withdraw(
connection: Connection,
wallet: Keypair,
mintAddress: string,
amount: number,
withdrawType: 'protected' | 'boosted' | 'regular' = 'protected'
): Promise<string> {
const serializedTx = await generateWithdrawTransaction({
owner: wallet.publicKey.toBase58(),
mintAddress,
amount,
withdrawType,
});
const txBuffer = Buffer.from(serializedTx, 'base64');
const transaction = VersionedTransaction.deserialize(txBuffer);
transaction.sign([wallet]);
const signature = await connection.sendTransaction(transaction);
await connection.confirmTransaction(signature, 'confirmed');
console.log('Withdrawal successful:', signature);
return signature;
}
TypeScript:获取账户余额
interface LuloPosition {
mint: string;
depositType: string;
balance: number;
interestEarned: number;
apy: number;
}
interface LuloAccount {
totalDeposited: number;
totalInterestEarned: number;
currentApy: number;
positions: LuloPosition[];
}
async function getAccountData(walletAddress: string): Promise<LuloAccount> {
const response = await fetch(
`${LULO_API_URL}/v1/account/${walletAddress}`,
{
headers: {
'x-api-key': process.env.LULO_API_KEY!,
},
}
);
if (!response.ok) {
throw new Error(`Failed to fetch account: ${response.statusText}`);
}
return response.json();
}
// Usage
const account = await getAccountData(wallet.publicKey.toBase58());
console.log('Total Deposited:', account.totalDeposited);
console.log('Interest Earned:', account.totalInterestEarned);
console.log('Current APY:', account.currentApy);
使用 Solana Agent Kit
import { SolanaAgentKit } from 'solana-agent-kit';
const agent = new SolanaAgentKit(
privateKey,
rpcUrl,
openAiApiKey
);
// Lend USDC using Lulo (gets best APR)
const signature = await agent.methods.lendAssets(
agent,
100 // amount of USDC to lend
);
console.log('Lending transaction:', signature);
Python:集成 Lulo
import aiohttp
import os
from solders.keypair import Keypair
from solders.transaction import VersionedTransaction
from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Confirmed
from solana.rpc.types import TxOpts
import base64
LULO_API_URL = "https://api.lulo.fi"
LULO_API_KEY = os.environ.get("LULO_API_KEY")
async def lulo_deposit(
client: AsyncClient,
wallet: Keypair,
mint_address: str,
amount: int,
deposit_type: str = "protected"
) -> str:
"""Deposit tokens to Lulo for yield optimization."""
async with aiohttp.ClientSession() as session:
# Generate deposit transaction
async with session.post(
f"{LULO_API_URL}/v1/generate.transactions.deposit?priorityFee=500000",
headers={
"Content-Type": "application/json",
"x-api-key": LULO_API_KEY,
},
json={
"owner": str(wallet.pubkey()),
"mintAddress": mint_address,
"depositType": deposit_type,
"amount": amount,
}
) as response:
if response.status != 200:
raise Exception(f"Deposit failed: {await response.text()}")
data = await response.json()
tx_data = base64.b64decode(data["transaction"])
# Deserialize, sign, and send
transaction = VersionedTransaction.from_bytes(tx_data)
transaction.sign([wallet])
signature = await client.send_transaction(
transaction,
opts=TxOpts(preflight_commitment=Confirmed)
)
await client.confirm_transaction(signature.value, commitment="confirmed")
return str(signature.value)
async def lulo_withdraw(
client: AsyncClient,
wallet: Keypair,
mint_address: str,
amount: int,
withdraw_type: str = "protected"
) -> str:
"""Withdraw tokens from Lulo."""
async with aiohttp.ClientSession() as session:
async with session.post(
f"{LULO_API_URL}/v1/generate.transactions.withdraw?priorityFee=500000",
headers={
"Content-Type": "application/json",
"x-api-key": LULO_API_KEY,
},
json={
"owner": str(wallet.pubkey()),
"mintAddress": mint_address,
"withdrawType": withdraw_type,
"amount": amount,
}
) as response:
if response.status != 200:
raise Exception(f"Withdrawal failed: {await response.text()}")
data = await response.json()
tx_data = base64.b64decode(data["transaction"])
transaction = VersionedTransaction.from_bytes(tx_data)
transaction.sign([wallet])
signature = await client.send_transaction(
transaction,
opts=TxOpts(preflight_commitment=Confirmed)
)
await client.confirm_transaction(signature.value, commitment="confirmed")
return str(signature.value)
# Usage
async def main():
client = AsyncClient("https://api.mainnet-beta.solana.com")
wallet = Keypair.from_base58_string("your-private-key")
USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
# Deposit 100 USDC
signature = await lulo_deposit(
client,
wallet,
USDC_MINT,
100_000_000, # 100 USDC
"protected"
)
print(f"Deposit: {signature}")
使用 Lulo Blinks
Lulo 还支持 Solana Actions/Blinks,简化交互操作:
// Blink endpoint for lending
const blinkUrl = `https://blink.lulo.fi/actions?amount=${amount}&symbol=USDC`;
// Fetch blink metadata
const response = await fetch(blinkUrl);
const blinkData = await response.json();
// Execute the action
const postResponse = await fetch(blinkUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ account: walletAddress }),
});
const { transaction } = await postResponse.json();
// Sign and send transaction...
常见代币地址
| 代币 | 铸造地址 |
|---|---|
| USDC | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| USDT | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |
| USDS | USDSwr9ApdHk5bvJKMjzff41FfuX8bSxdKcR81vTwcA |
| PYUSD | 2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo |
| SOL(包装型) | So11111111111111111111111111111111111111112 |
| mSOL | mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So |
| JitoSOL | J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn |
| bSOL | bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1 |
最佳实践
安全性
- 切勿公开 API 密钥 - 使用环境变量
- 验证交易 - 签名前先模拟交易
- 设置合适的滑点 - 考虑汇率变化
- 监控持仓 - 定期检查余额和 APY
性能
- 使用优先费 - 使用 500,000+ 微 lamport 以加快确认速度
- 批量操作 - 尽可能合并多个操作
- 缓存池数据 - 利率每小时更新,请适当缓存
错误处理
try {
const signature = await deposit(connection, wallet, USDC_MINT, amount, 'protected');
} catch (error) {
if (error.message.includes('BAD_REQUEST')) {
console.error('Invalid parameters');
} else if (error.message.includes('UNAUTHORIZED')) {
console.error('Invalid API key');
} else if (error.message.includes('NOT_FOUND')) {
console.error('Account or pool not found');
} else {
throw error;
}
}
监控 APY
async function monitorRates(interval: number = 3600000) { // 1 hour
setInterval(async () => {
const pools = await fetch(`${LULO_API_URL}/v1/pools`, {
headers: { 'x-api-key': process.env.LULO_API_KEY! },
}).then(r => r.json());
pools.pools.forEach(pool => {
console.log(`${pool.symbol}: Protected ${pool.protectedApy}% | Boosted ${pool.boostedApy}%`);
});
}, interval);
}
费用结构
| 费用类型 | 金额 | 适用时间 |
|---|---|---|
| 初始化 | 0.005 SOL | 仅首次存款 |
| 管理 | 无 | - |
| 提款 | 无 | - |
| 交易 | 可变 | 每笔交易(Solana 费用) |
资源
技能结构
lulo/
├── SKILL.md # This file
├── resources/
│ ├── api-reference.md # Complete API documentation
│ └── token-addresses.md # Supported token addresses
├── examples/
│ ├── deposit/
│ │ └── deposit.ts # Deposit examples
│ ├── withdraw/
│ │ └── withdraw.ts # Withdrawal examples
│ ├── balance/
│ │ └── balance.ts # Balance query examples
│ └── integration/
│ └── full-integration.ts # Complete integration example
├── templates/
│ └── lulo-client.ts # Ready-to-use client template
└── docs/
└── troubleshooting.md # Common issues and solutions