Getting Started
This guide will walk you through setting up and using the Suilend SDK to interact with the Suilend lending protocol on Sui.
Prerequisites
Node.js 16+ or Bun
Basic knowledge of TypeScript/JavaScript
A Sui wallet with some SUI tokens for gas fees
Installation
Install the SDK and peer dependencies:
npm install @suilend/sdk @mysten/[email protected] @mysten/[email protected] @suilend/sui-fe@^0.3.5
Set up your environment:
Create a .env
file in your project root:
# Optional: Use beta market for testing
NEXT_PUBLIC_SUILEND_USE_BETA_MARKET=false
# Your Sui RPC endpoint (optional, defaults to mainnet)
SUI_RPC_URL=https://fullnode.mainnet.sui.io
Basic Setup
1. Initialize the Client
import {
SuilendClient,
LENDING_MARKET_ID,
LENDING_MARKET_TYPE,
} from "@suilend/sdk";
import { SuiClient } from "@mysten/sui/client";
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
// Initialize Sui client
const suiClient = new SuiClient({
url: process.env.SUI_RPC_URL || "https://fullnode.mainnet.sui.io",
});
// Initialize Suilend client
const suilendClient = await SuilendClient.initialize(
LENDING_MARKET_ID,
LENDING_MARKET_TYPE,
suiClient
);
// Set up your keypair (in production, load from secure storage)
const keypair = Ed25519Keypair.fromSecretKey(/* your secret key */);
const userAddress = keypair.toSuiAddress();
2. Check Your Existing Obligations
Before performing any operations, check if you already have obligations:
async function checkExistingObligations() {
try {
const obligationOwnerCaps = await SuilendClient.getObligationOwnerCaps(
userAddress,
[LENDING_MARKET_TYPE],
suiClient
);
console.log(`Found ${obligationOwnerCaps.length} existing obligations`);
for (const cap of obligationOwnerCaps) {
const obligation = await SuilendClient.getObligation(
cap.obligationId,
[LENDING_MARKET_TYPE],
suiClient
);
console.log("Obligation:", {
id: cap.obligationId,
deposits: obligation.deposits.length,
borrows: obligation.borrows.length,
});
}
return obligationOwnerCaps;
} catch (error) {
console.log("No existing obligations found");
return [];
}
}
Tutorial 1: Your First Deposit
Let's start by depositing SUI tokens to earn interest:
async function firstDeposit() {
const transaction = new Transaction();
try {
// Step 1: Create an obligation (if you don't have one)
const existingCaps = await checkExistingObligations();
let obligationOwnerCap;
if (existingCaps.length === 0) {
console.log("Creating new obligation...");
obligationOwnerCap = suilendClient.createObligation(transaction);
} else {
console.log("Using existing obligation...");
obligationOwnerCap = existingCaps[0].id;
}
// Step 2: Deposit 1 SUI into the obligation as collateral
await suilendClient.depositIntoObligation(
userAddress,
"0x2::sui::SUI", // SUI coin type
"1000000000", // 1 SUI in MIST (1 SUI = 10^9 MIST)
transaction,
obligationOwnerCap
);
// Step 3: Execute the transaction
const result = await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction,
options: {
showEffects: true,
showEvents: true,
},
});
console.log("Deposit successful!");
console.log("Transaction digest:", result.digest);
return result;
} catch (error) {
console.error("Deposit failed:", error.message);
throw error;
}
}
// Run the deposit
await firstDeposit();
Tutorial 2: Borrowing Against Your Collateral
Now let's borrow USDC against your SUI collateral:
async function borrowExample() {
const transaction = new Transaction();
try {
// Step 1: Get your obligation
const obligationOwnerCaps = await SuilendClient.getObligationOwnerCaps(
userAddress,
[LENDING_MARKET_TYPE],
suiClient
);
if (obligationOwnerCaps.length === 0) {
throw new Error("No obligations found. Please deposit first.");
}
const obligationOwnerCap = obligationOwnerCaps[0];
const obligation = await SuilendClient.getObligation(
obligationOwnerCap.obligationId,
[LENDING_MARKET_TYPE],
suiClient
);
// Step 2: Refresh the obligation state
await suilendClient.refreshAll(transaction, obligation);
// Step 3: Borrow 0.5 USDC (assuming USDC has 6 decimals)
const borrowResult = await suilendClient.borrow(
obligationOwnerCap.id,
obligationOwnerCap.obligationId,
"0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN", // USDC coin type
"500000", // 0.5 USDC in smallest denomination
transaction
);
// Step 4: Send borrowed tokens to yourself
transaction.transferObjects([borrowResult], userAddress);
// Step 5: Execute the transaction
const result = await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction,
options: {
showEffects: true,
showEvents: true,
},
});
console.log("Borrow successful!");
console.log("Transaction digest:", result.digest);
return result;
} catch (error) {
console.error("Borrow failed:", error.message);
throw error;
}
}
// Run the borrow
await borrowExample();
Tutorial 3: Claiming Rewards
Claim rewards from liquidity mining programs:
import { Side } from "@suilend/sdk";
async function claimRewardsExample() {
const transaction = new Transaction();
try {
// Step 1: Get your obligation
const obligationOwnerCaps = await SuilendClient.getObligationOwnerCaps(
userAddress,
[LENDING_MARKET_TYPE],
suiClient
);
if (obligationOwnerCaps.length === 0) {
throw new Error("No obligations found.");
}
const obligationOwnerCap = obligationOwnerCaps[0];
// Step 2: Define rewards to claim
// You'll need to know which reserves have active rewards
const rewards = [
{
reserveArrayIndex: 0n, // SUI reserve (usually index 0)
rewardIndex: 0n, // First reward program
rewardCoinType: "0x2::sui::SUI", // Reward is paid in SUI
side: Side.DEPOSIT, // Reward for deposits
},
// Add more rewards as needed
];
// Step 3: Claim rewards and send to user
suilendClient.claimRewardsAndSendToUser(
userAddress,
obligationOwnerCap.id,
rewards,
transaction
);
// Step 4: Execute the transaction
const result = await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction,
options: {
showEffects: true,
showEvents: true,
},
});
console.log("Rewards claimed successfully!");
console.log("Transaction digest:", result.digest);
return result;
} catch (error) {
console.error("Claim rewards failed:", error.message);
throw error;
}
}
Tutorial 4: Repaying Your Loan
Repay borrowed tokens to reduce your debt:
async function repayExample() {
const transaction = new Transaction();
try {
// Step 1: Get your obligation
const obligationOwnerCaps = await SuilendClient.getObligationOwnerCaps(
userAddress,
[LENDING_MARKET_TYPE],
suiClient
);
const obligationOwnerCap = obligationOwnerCaps[0];
// Step 2: Repay 0.25 USDC
await suilendClient.repayIntoObligation(
userAddress,
obligationOwnerCap.obligationId,
"0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN", // USDC
"250000", // 0.25 USDC
transaction
);
// Step 3: Execute the transaction
const result = await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction,
options: {
showEffects: true,
showEvents: true,
},
});
console.log("Repayment successful!");
console.log("Transaction digest:", result.digest);
return result;
} catch (error) {
console.error("Repayment failed:", error.message);
throw error;
}
}
Tutorial 5: Withdrawing Your Collateral
Withdraw your deposited collateral:
async function withdrawExample() {
const transaction = new Transaction();
try {
// Step 1: Get your obligation
const obligationOwnerCaps = await SuilendClient.getObligationOwnerCaps(
userAddress,
[LENDING_MARKET_TYPE],
suiClient
);
const obligationOwnerCap = obligationOwnerCaps[0];
const obligation = await SuilendClient.getObligation(
obligationOwnerCap.obligationId,
[LENDING_MARKET_TYPE],
suiClient
);
// Step 2: Refresh obligation state
await suilendClient.refreshAll(transaction, obligation);
// Step 3: Withdraw and send to user (automatically redeems cTokens)
await suilendClient.withdrawAndSendToUser(
userAddress,
obligationOwnerCap.id,
obligationOwnerCap.obligationId,
"0x2::sui::SUI",
"500000000", // 0.5 SUI
transaction
);
// Step 4: Execute the transaction
const result = await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction,
options: {
showEffects: true,
showEvents: true,
},
});
console.log("Withdrawal successful!");
console.log("Transaction digest:", result.digest);
return result;
} catch (error) {
console.error("Withdrawal failed:", error.message);
throw error;
}
}
Complete Example: Full Lending Flow
Here's a complete example that demonstrates the full lending lifecycle:
import {
SuilendClient,
LENDING_MARKET_ID,
LENDING_MARKET_TYPE,
Side,
} from "@suilend/sdk";
import { SuiClient } from "@mysten/sui/client";
import { Transaction } from "@mysten/sui/transactions";
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
async function fullLendingFlow() {
// Initialize clients
const suiClient = new SuiClient({ url: "https://fullnode.mainnet.sui.io" });
const suilendClient = await SuilendClient.initialize(
LENDING_MARKET_ID,
LENDING_MARKET_TYPE,
suiClient
);
// Set up keypair (replace with your actual key management)
const keypair = Ed25519Keypair.fromSecretKey(/* your secret key */);
const userAddress = keypair.toSuiAddress();
console.log("Starting full lending flow for address:", userAddress);
try {
// 1. Create obligation
console.log("1. Creating obligation...");
const createTx = new Transaction();
const obligationOwnerCap = suilendClient.createObligation(createTx);
await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction: createTx,
});
console.log("✓ Obligation created");
// 2. Deposit collateral
console.log("2. Depositing SUI as collateral...");
const depositTx = new Transaction();
await suilendClient.depositIntoObligation(
userAddress,
"0x2::sui::SUI",
"5000000000", // 5 SUI
depositTx,
obligationOwnerCap
);
await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction: depositTx,
});
console.log("✓ 5 SUI deposited as collateral");
// 3. Borrow against collateral
console.log("3. Borrowing USDC...");
const borrowTx = new Transaction();
// Get the obligation ID (in real app, you'd store this)
const caps = await SuilendClient.getObligationOwnerCaps(
userAddress,
[LENDING_MARKET_TYPE],
suiClient
);
const obligationId = caps[0].obligationId;
const obligation = await SuilendClient.getObligation(
obligationId,
[LENDING_MARKET_TYPE],
suiClient
);
// Refresh before borrowing
await suilendClient.refreshAll(borrowTx, obligation);
await suilendClient.borrowAndSendToUser(
userAddress,
obligationOwnerCap,
obligationId,
"0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN",
"1000000", // 1 USDC
borrowTx
);
await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction: borrowTx,
});
console.log("✓ 1 USDC borrowed");
// 4. Wait some time for rewards to accrue (in real app)
console.log("4. Claiming rewards...");
const rewardsTx = new Transaction();
const rewards = [
{
reserveArrayIndex: 0n,
rewardIndex: 0n,
rewardCoinType: "0x2::sui::SUI",
side: Side.DEPOSIT,
},
];
try {
suilendClient.claimRewardsAndSendToUser(
userAddress,
obligationOwnerCap,
rewards,
rewardsTx
);
await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction: rewardsTx,
});
console.log("✓ Rewards claimed");
} catch (error) {
console.log("No rewards available to claim");
}
// 5. Repay part of the loan
console.log("5. Repaying loan...");
const repayTx = new Transaction();
await suilendClient.repayIntoObligation(
userAddress,
obligationId,
"0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN",
"500000", // 0.5 USDC
repayTx
);
await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction: repayTx,
});
console.log("✓ 0.5 USDC repaid");
// 6. Withdraw some collateral
console.log("6. Withdrawing collateral...");
const withdrawTx = new Transaction();
// Refresh obligation before withdrawal
const updatedObligation = await SuilendClient.getObligation(
obligationId,
[LENDING_MARKET_TYPE],
suiClient
);
await suilendClient.refreshAll(withdrawTx, updatedObligation);
await suilendClient.withdrawAndSendToUser(
userAddress,
obligationOwnerCap,
obligationId,
"0x2::sui::SUI",
"1000000000", // 1 SUI
withdrawTx
);
await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction: withdrawTx,
});
console.log("✓ 1 SUI withdrawn");
console.log("🎉 Full lending flow completed successfully!");
} catch (error) {
console.error("❌ Error in lending flow:", error.message);
throw error;
}
}
// Run the full flow
fullLendingFlow().catch(console.error);
Best Practices
1. Error Handling
Always wrap SDK calls in try-catch blocks and handle specific error cases:
try {
await suilendClient.depositIntoObligation(/* ... */);
} catch (error) {
if (error.message.includes("insufficient funds")) {
console.error("Not enough tokens in wallet");
} else if (error.message.includes("gas budget")) {
console.error("Increase gas budget");
} else {
console.error("Unexpected error:", error);
}
}
2. Gas Management
Set appropriate gas budgets for complex transactions:
const transaction = new Transaction();
// Add your operations...
transaction.setGasBudget(10000000); // 0.01 SUI
await suiClient.signAndExecuteTransaction({
signer: keypair,
transaction,
});
3. State Refreshing
Always refresh obligation state before operations that depend on current prices:
const obligation = await SuilendClient.getObligation(
obligationId,
[LENDING_MARKET_TYPE],
suiClient
);
await suilendClient.refreshAll(transaction, obligation);
// Now perform your operations...
4. Batching Operations
Combine multiple operations in a single transaction for better gas efficiency:
const transaction = new Transaction();
// Refresh state
await suilendClient.refreshAll(transaction, obligation);
// Claim rewards
suilendClient.claimRewards(userAddress, obligationOwnerCap, rewards, transaction);
// Deposit claimed rewards
await suilendClient.depositIntoObligation(/* ... */, transaction, obligationOwnerCap);
// Execute all in one transaction
await suiClient.signAndExecuteTransaction({ signer: keypair, transaction });
Next Steps
Read the API Reference for detailed method documentation
Explore the main README for advanced features
Check out the admin functions for protocol management
Join our Discord for support
Common Issues
"Obligation not found"
Make sure you're using the correct lending market type arguments
Verify the obligation ID exists and belongs to your address
"Insufficient collateral"
Check your collateral ratio before borrowing
Add more collateral or repay some debt
"Price staleness"
Call
refreshAll()
to update price feedsCheck if Pyth price feeds are working properly
"Gas budget exceeded"
Increase your gas budget for complex transactions
Consider splitting operations across multiple transactions