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

  1. Install the SDK and peer dependencies:


npm install @suilend/sdk @mysten/[email protected] @mysten/[email protected] @suilend/sui-fe@^0.3.5
  1. 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 feeds

  • Check if Pyth price feeds are working properly

"Gas budget exceeded"

  • Increase your gas budget for complex transactions

  • Consider splitting operations across multiple transactions