Scallop Lend Integration
Comprehensive guide for integrating Scallop lending protocol into your applications using TypeScript or Python SDKs.
Overview
Scallop is the leading lending protocol on Sui blockchain. This skill covers:
- Deposits: Supply assets to earn interest
- Withdrawals: Redeem market coins for underlying assets
- Borrowing: Borrow against collateral
- Repayment: Repay borrowed amounts
- Collateral Management: Add/remove collateral
Terminology Note
Important: The SDK distinguishes between lending pool operations and collateral operations:
Operation Method Purpose Supply to Lending Pool supply()/supplyQuick()Earn interest, receive market coins Deposit Collateral depositCollateral()/depositCollateralQuick()Enable borrowing, no direct yield
Quick Start
Installation
# Python (0.3.0a1 is an alpha pre-release, so --pre is required)
pip install --pre sui-scallop-sdk
# TypeScript
npm install @scallop-io/sui-scallop-sdk
Initialize Client
# Python
from sui_scallop_sdk import ScallopClient
client = ScallopClient(
secret_key="your_private_key",
network="mainnet" # or "testnet"
)
// TypeScript
import { Scallop } from '@scallop-io/sui-scallop-sdk';
const scallop = new Scallop({
secretKey: 'your_private_key',
networkType: 'mainnet'
});
await scallop.init();
Core Operations
1. Supply (Supply Assets)
Supply assets to earn interest and receive market coins.
# Python - Supply 1 SUI
builder = client.create_builder()
tx = builder.create_tx_block()
# Quick method (handles coin selection + oracle updates)
market_coin_idx = tx.supply_quick(
amount=1_000_000_000, # 1 SUI (9 decimals)
coin_name="sui",
sender=client.wallet_address
)
# Transfer market coin to yourself
tx.transfer_objects([market_coin_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
print(f"Supply TX: {result.digest}")
// TypeScript - Supply 1 SUI
const builder = await scallop.createScallopBuilder();
const tx = builder.createTxBlock();
await tx.supplyQuick(1_000_000_000, 'sui');
tx.transferObjects([tx.getReturnedMarketCoin()], sender);
const result = await builder.signAndSendTxBlock(tx);
2. Withdraw (Redeem Assets)
Redeem market coins for underlying assets.
# Python - Withdraw 1 SUI worth of market coins
tx = builder.create_tx_block()
underlying_idx = tx.withdraw_quick(
amount=1_000_000_000,
coin_name="sui",
sender=client.wallet_address
)
tx.transfer_objects([underlying_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
// TypeScript - Withdraw 1 SUI
const tx = builder.createTxBlock();
await tx.withdrawQuick(1_000_000_000, 'sui');
3. Create Obligation
Before borrowing, create an obligation account.
# Python - Create obligation
tx = builder.create_tx_block()
# create_obligation() returns a single int (command index)
obligation_idx = tx.create_obligation()
# Transfer the obligation key to yourself
tx.transfer_objects([obligation_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
# Parse obligation_id and obligation_key from result.created_objects
// TypeScript - Create obligation
const client = await scallop.createScallopClient();
const result = await client.openObligation();
// Parse obligationId and obligationKey from result
4. Deposit Collateral
Deposit assets as collateral to your obligation.
# Python - Deposit 10 SUI as collateral
tx = builder.create_tx_block()
tx.deposit_collateral_quick(
amount=10_000_000_000, # 10 SUI
coin_name="sui",
obligation_id=obligation_id,
sender=client.wallet_address
)
result = builder.sign_and_send_tx_block(tx)
// TypeScript - Deposit 10 SUI as collateral
const tx = builder.createTxBlock();
await tx.depositCollateralQuick(10_000_000_000, 'sui', obligationId);
const result = await builder.signAndSendTxBlock(tx);
5. Borrow
Borrow assets against your collateral.
# Python - Borrow 100 USDC
tx = builder.create_tx_block()
borrowed_coin_idx = tx.borrow_quick(
amount=100_000_000, # 100 USDC (6 decimals)
coin_name="usdc",
obligation_id=obligation_id,
obligation_key=obligation_key,
)
tx.transfer_objects([borrowed_coin_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
// TypeScript - Borrow 100 USDC
const tx = builder.createTxBlock();
const borrowedCoin = await tx.borrowQuick(100_000_000, 'usdc', obligationId, obligationKey);
tx.transferObjects([borrowedCoin], sender);
const result = await builder.signAndSendTxBlock(tx);
6. Repay
Repay borrowed amounts to reduce debt.
# Python - Repay 50 USDC
tx = builder.create_tx_block()
tx.repay_quick(
amount=50_000_000, # 50 USDC
coin_name="usdc",
obligation_id=obligation_id,
sender=client.wallet_address
)
result = builder.sign_and_send_tx_block(tx)
// TypeScript - Repay 50 USDC
const tx = builder.createTxBlock();
await tx.repayQuick(50_000_000, 'usdc', obligationId);
const result = await builder.signAndSendTxBlock(tx);
7. Withdraw Collateral
Remove collateral (only if position remains healthy).
# Python - Withdraw 5 SUI collateral
tx = builder.create_tx_block()
withdrawn_idx = tx.withdraw_collateral_quick(
amount=5_000_000_000, # 5 SUI
coin_name="sui",
obligation_id=obligation_id,
obligation_key=obligation_key,
)
tx.transfer_objects([withdrawn_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
// TypeScript - Withdraw 5 SUI collateral
const tx = builder.createTxBlock();
const withdrawnCoin = await tx.takeCollateralQuick(
5_000_000_000, 'sui', obligationId, obligationKey
);
tx.transferObjects([withdrawnCoin], sender);
const result = await builder.signAndSendTxBlock(tx);
Deprecated Method Names
Important: The following old method names are deprecated since SDK v0.2.0. They still work but will be removed in a future release. Use the new names instead.
Deprecated Replacement deposit()/deposit_quick()supply()/supply_quick()add_collateral()/add_collateral_quick()deposit_collateral()/deposit_collateral_quick()The rename clarifies that "supply" earns interest in the lending pool, while "deposit collateral" enables borrowing.
Quick Methods vs Standard Methods
| Method Type | Oracle Update | Coin Selection | Use Case |
|---|---|---|---|
*_quick |
Automatic | Automatic | Simple operations |
| Standard | Manual | Manual | Complex transactions |
When to Use Standard Methods
Use standard methods for:
- Custom coin selection
- Multi-step transactions
- Gas optimization
- Advanced composability
# Standard method - more control
tx.supply(
coin_input_idx=coin_idx, # Index from add_object_input() or a prior result
coin_name="sui",
coin_is_result=False, # True if coin_input_idx is a Result index
)
Supported Assets
See Supported Coins Reference for full list.
Common assets:
- SUI: Native token (9 decimals)
- USDC: Circle USD (6 decimals)
- wETH: Wrapped Ether (8 decimals)
- wBTC: Wrapped Bitcoin (8 decimals)
- afSUI/haSUI: Liquid staking tokens (9 decimals)
- SCA/DEEP: DeFi tokens with 70% collateral weight
Risk Considerations
Health Factor
health_factor = total_collateral_value * collateral_factor / total_debt_value
- > 1.0: Position is safe
- < 1.0: Position is liquidatable
Collateral Factors
Each asset has a collateral factor (0.0 - 0.9):
- SUI: 0.80 (can borrow 80% of value)
- USDC: 0.90 (can borrow 90% of value)
- wETH: 0.80
Best Practices
- Monitor Health: Check position health regularly
- Buffer Zone: Maintain health factor > 1.2 for safety
- Price Volatility: Consider asset volatility when borrowing
- Interest Rates: Check current borrow APY before borrowing
Manual Interest Accrual (Advanced)
On-chain interest is settled lazily — every state-changing user op (supply, borrow, repay, withdraw_collateral, liquidate, …) calls into accrue_interest_for_market or accrue_interest_for_market_and_obligation first. Two scenarios where you may want to call these explicitly via a PTB instead of relying on the implicit accrual:
- Reading "fresh" market or obligation state in the same transaction — e.g. an analytics keeper that snapshots
Market+Obligationafter settlement without touching any user op. - Multi-obligation batches where you want one accrual block at the head of the PTB to avoid re-accruing per inner op.
The Move entrypoints (mainnet protocol::accrue_interest):
| Function | Effect |
|---|---|
accrue_interest_for_market(version, market, clock) |
Updates global interest for every supported asset in the market |
accrue_interest_for_market_and_obligation(version, market, obligation, clock) |
Above + recomputes the obligation's per-asset debt with the new index |
Source: sui-lending-protocol/contracts/protocol/sources/user/accrue_interest.move.
Example (TypeScript builder)
const tx = builder.createTxBlock();
tx.moveCall({
target: `${protocolPackage}::accrue_interest::accrue_interest_for_market_and_obligation`,
arguments: [
tx.object(versionId),
tx.object(marketId),
tx.object(obligationId),
tx.object('0x6'), // clock
],
});
// Now any read or compose downstream sees fully accrued state.
await builder.signAndSendTxBlock(tx);
As of TS SDK v4.3.0 and Python
sui-scallop-sdk0.3.0a1, neither SDK exposes dedicated helpers for these — drop down to a rawmoveCall(or use advanced-transactions). For most application code the implicit accrual from*_quickmethods is sufficient — only reach for these when you need an accrual-only PTB.
Error Handling
Common errors and solutions:
| Error | Cause | Solution |
|---|---|---|
CollateralFactorExceeded |
Borrow exceeds limit | Add more collateral |
InsufficientLiquidity |
Market lacks funds | Reduce borrow amount |
OraclePriceStale |
Price outdated | Use quick methods |
from sui_scallop_sdk.exceptions import ScallopError
try:
result = builder.sign_and_send_tx_block(tx)
except ScallopError as e:
print(f"Error {e.code}: {e.message}")
Complete Example
Full lending cycle: deposit, borrow, repay, withdraw.
from sui_scallop_sdk import ScallopClient
# Initialize
client = ScallopClient(secret_key="...", network="mainnet")
builder = client.create_builder()
# 1. Supply 10 SUI and get market coins
tx1 = builder.create_tx_block()
market_coin = tx1.supply_quick(10_000_000_000, "sui", client.wallet_address)
tx1.transfer_objects([market_coin], client.wallet_address)
result1 = builder.sign_and_send_tx_block(tx1)
# 2. Create obligation
tx2 = builder.create_tx_block()
obligation_idx = tx2.create_obligation()
tx2.transfer_objects([obligation_idx], client.wallet_address)
result2 = builder.sign_and_send_tx_block(tx2)
# Parse obligation_id and obligation_key from result2.created_objects
# 3. Add collateral and borrow
tx3 = builder.create_tx_block()
tx3.deposit_collateral_quick(10_000_000_000, "sui", obligation_id, client.wallet_address)
borrowed = tx3.borrow_quick(100_000_000, "usdc", obligation_id, obligation_key)
tx3.transfer_objects([borrowed], client.wallet_address)
result3 = builder.sign_and_send_tx_block(tx3)
# 4. Repay and withdraw collateral
tx4 = builder.create_tx_block()
tx4.repay_quick(100_000_000, "usdc", obligation_id, client.wallet_address)
withdrawn = tx4.withdraw_collateral_quick(
10_000_000_000, "sui", obligation_id, obligation_key
)
tx4.transfer_objects([withdrawn], client.wallet_address)
result4 = builder.sign_and_send_tx_block(tx4)
print("Lending cycle complete!")
References
- SDK Patterns - Detailed SDK usage patterns
- Transaction Flow - Transaction building guide
- Quick Methods - Quick method reference
- Supported Coins - All supported assets
- Error Codes - Error reference