Python SDK for Scallop Lending Protocol on Sui
Project description
Scallop Python SDK
A Python SDK for interacting with the Scallop Lending Protocol on Sui blockchain.
English | 繁體中文
Features
Core Lending Operations
- Supply/Withdraw: supply, withdraw (supply assets to earn interest)
- Borrow/Repay: borrow, repay
- Collateral Management: deposit_collateral, withdraw_collateral
- Liquidation: liquidate
- Flash Loans: borrow_flash_loan, repay_flash_loan
Quick Methods
- Auto Coin Selection: supply_quick, withdraw_quick, repay_quick
- Auto Price Update: borrow_quick, liquidate_quick
- Oracle Update: update_asset_prices_quick
- veSCA Lifecycle Helpers: lock_sca_quick, extend_lock_period_quick, extend_lock_amount_quick, renew_expired_vesca_quick, redeem_sca_quick, split_vesca_quick, merge_vesca_quick
Advanced Features
- Staking Pool (Spool): Stake market coins for rewards
- sCoin: Mint/burn sCoin
- veSCA: Lock SCA for veSCA
- Borrow Incentive: Stake obligations for rewards
- Referral: Referral system
- Loyalty Program: Loyalty rewards
Infrastructure
- Cryptography: Ed25519 signing, address derivation, Bech32 key import (
suiprivkey1...) - BCS Serialization: Full transaction serialization support (mainnet verified)
- Oracle Integration: Pyth + X Oracle
Installation
pip install sui-scallop-sdk
# Or install from source
git clone https://github.com/scallop-io/sui-scallop-sdk-python
cd sui-scallop-sdk-python
pip install -e .
Quick Start
Query Obligation
from sui_scallop_sdk import ScallopClient
# Initialize client
client = ScallopClient(network="mainnet")
# Query obligation
query = client.create_query()
obligation = query.get_obligation("0x...")
print(f"Risk Level: {obligation.risk_level}")
print(f"Is Liquidatable: {obligation.is_liquidatable}")
print(f"Total Debt USD: ${obligation.total_debt_usd}")
print(f"Total Collateral USD: ${obligation.total_collateral_usd}")
Query Market And TVL
from sui_scallop_sdk import ScallopClient
client = ScallopClient(network="mainnet")
query = client.create_query()
pool = query.get_market_pool("sui")
collateral = query.get_market_collateral("sui")
pool_address = query.get_pool_address("sui")
tvl = query.get_tvl()
prices = query.get_coin_prices(["sui", "sca", "usdc"])
print(pool.supply_amount, pool.borrow_amount, pool.supply_apy)
print(collateral.deposit_amount, collateral.collateral_factor)
print(pool_address.lending_pool_address, pool_address.flash_loan_fee_object)
print(tvl.total_value)
print(prices)
Query Portfolio And Lendings
from sui_scallop_sdk import ScallopClient
client = ScallopClient.from_env()
query = client.create_query()
portfolio = query.get_user_portfolio(client.wallet_address)
lendings = query.get_lendings(client.wallet_address)
print(portfolio.total_supply_value, portfolio.total_borrow_value, portfolio.net_apy)
print(portfolio.obligations)
print(lendings)
Query Spool, sCoin, veSCA, And Loyalty
from sui_scallop_sdk import ScallopClient
client = ScallopClient.from_env()
query = client.create_query()
spool = query.get_spool("ssui")
scoin_supply = query.get_scoin_total_supply("sui")
scoin_amounts = query.get_scoin_amounts(["ssui", "susdc"], client.wallet_address)
vescas = query.get_vescas(client.wallet_address, exclude_empty=True)
print(spool.reward_apr if spool else None)
print(scoin_supply, scoin_amounts)
if vescas:
loyalty = query.get_loyalty_program_info(vescas[0].key_id)
vesca_loyalty = query.get_vesca_loyalty_program_info(vescas[0].key_id)
print(vescas[0].locked_sca_amount, vescas[0].current_vesca_balance)
print(loyalty.pending_reward, vesca_loyalty.pending_vesca_reward)
For a runnable walkthrough, see examples/query_example.py.
Supply (Earn Interest)
from sui_scallop_sdk import ScallopClient
# Initialize with wallet credentials
# Supports: suiprivkey1... (bech32), base64, hex, or raw bytes
client = ScallopClient(
secret_key="suiprivkey1...",
network="mainnet",
)
# Create transaction
builder = client.create_builder()
tx = builder.create_tx_block()
# Supply 1 SUI to lending pool
market_coin_idx = tx.supply(coin_input_idx=0, coin_name="sui")
tx.transfer_objects([market_coin_idx], client.wallet_address)
# Execute
result = builder.sign_and_send_tx_block(tx)
if result.success:
print(f"Success! TX: {result.digest}")
else:
print(f"Failed: {result.error}")
Quick Supply (Auto Coin Selection)
tx = builder.create_tx_block()
# Use supply_quick for automatic coin selection
market_coin_idx = tx.supply_quick(
amount=1_000_000_000, # 1 SUI (9 decimals)
coin_name="sui",
sender=client.wallet_address
)
tx.transfer_objects([market_coin_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
Initialize From Environment
export NETWORK=mainnet
export PRIVATE_KEY="suiprivkey1..."
# Optional when you want to override the derived address
export WALLET_ADDRESS="0x..."
from sui_scallop_sdk import ScallopClient
client = ScallopClient.from_env()
PRIVATE_KEY is supported for config-driven initialization. MNEMONIC is not yet supported.
Borrow
tx = builder.create_tx_block()
# Borrow with automatic oracle price update
borrowed_coin_idx = tx.borrow_quick(
amount=100_000_000, # 100 USDC (6 decimals)
coin_name="usdc",
obligation_id="0x...",
obligation_key="0x...",
)
tx.transfer_objects([borrowed_coin_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
Repay
tx = builder.create_tx_block()
# Auto coin selection for repay
tx.repay_quick(
amount=50_000_000, # Repay 50 USDC
coin_name="usdc",
obligation_id="0x...",
sender=client.wallet_address,
)
result = builder.sign_and_send_tx_block(tx)
Flash Loan
tx = builder.create_tx_block()
# Borrow flash loan (returns TxResult objects for PTB tuple outputs)
coin_result, receipt_result = tx.borrow_flash_loan(
amount=1_000_000_000, # 1 SUI
coin_name="sui"
)
# ... perform arbitrage or other operations ...
# Repay (must be in same transaction, includes fee)
tx.repay_flash_loan(coin_result, receipt_result, "sui")
result = builder.sign_and_send_tx_block(tx)
Liquidation
tx = builder.create_tx_block()
# Auto coin selection liquidation (auto updates oracle prices)
remaining_debt_idx, collateral_idx = tx.liquidate_quick(
obligation_id="0x...",
repay_amount=100_000_000, # 100 USDC
debt_coin_name="usdc",
collateral_coin_name="sui",
sender=client.wallet_address,
)
# Transfer received collateral
tx.transfer_objects(
[{"kind": "NestedResult", "index": collateral_idx, "resultIndex": 1}],
client.wallet_address,
)
result = builder.sign_and_send_tx_block(tx)
Advanced Features
Spool Staking
tx = builder.create_tx_block()
# Create stake account
stake_account_idx = tx.create_stake_account(stake_pool_id, "sui")
# Stake market coin
tx.stake_spool(
stake_account_id="0x...",
stake_pool_id="0x...",
coin_input_idx=market_coin_idx,
coin_name="sui"
)
# Claim rewards
reward_idx = tx.claim_spool_rewards(
stake_account_id="0x...",
stake_pool_id="0x...",
reward_pool_id="0x...",
coin_name="sca"
)
tx.transfer_objects([reward_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
veSCA Lock
tx = builder.create_tx_block()
# Lock SCA to get veSCA key (365 days)
vesca_key_idx = tx.lock_sca(
sca_coin_idx=sca_coin_input,
lock_period_days=365
)
tx.transfer_objects([vesca_key_idx], client.wallet_address)
# Extend lock period
tx.extend_lock_period(
vesca_key_id="0x...",
new_unlock_at=new_unlock_timestamp # Unix epoch in seconds
)
# Add more SCA to existing lock
tx.extend_lock_amount(
vesca_key_id="0x...",
sca_coin_idx=additional_sca_input
)
# Redeem SCA (after lock expires)
sca_idx = tx.redeem_sca(vesca_key_id="0x...")
tx.transfer_objects([sca_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
veSCA Quick Methods
tx = builder.create_tx_block()
# Initial lock with automatic SCA coin selection
new_vesca_idx = tx.lock_sca_quick(
amount=10_000_000_000, # 10 SCA in raw units
lock_period_days=365,
sender=client.wallet_address,
)
tx.transfer_objects([new_vesca_idx], client.wallet_address)
# Extend only the lock duration of the highest-balance veSCA
tx.extend_lock_period_quick(
lock_period_days=30,
sender=client.wallet_address,
)
# Top up an existing veSCA with automatic coin selection
tx.extend_lock_amount_quick(
sca_amount=1_000_000_000, # 1 SCA in raw units
sender=client.wallet_address,
vesca_key_id="0x...", # optional, defaults to the sender's highest-balance veSCA
)
# Renew an expired veSCA
tx.renew_expired_vesca_quick(
sca_amount=10_000_000_000,
lock_period_days=180,
sender=client.wallet_address,
vesca_key_id="0x...",
)
# Redeem unlocked SCA and auto-transfer it back to the sender
tx.redeem_sca_quick(
sender=client.wallet_address,
vesca_key_id="0x...",
)
# Split a veSCA key and auto-transfer the new key NFT
tx.split_vesca_quick(
split_amount=5_000_000_000,
vesca_key_id="0x...",
sender=client.wallet_address,
)
# Merge two veSCA keys, aligning unlock times automatically when needed
tx.merge_vesca_quick(
target_vesca_key_id="0x...",
source_vesca_key_id="0x...",
)
result = builder.sign_and_send_tx_block(tx)
Notes:
- veSCA quick methods stay builder-first in Python, so methods that need coin selection or auto-transfer still require an explicit
sender vesca_key_idis optional forlock_sca_quick,extend_lock_period_quick,extend_lock_amount_quick,renew_expired_vesca_quick, andredeem_sca_quick- when
vesca_key_idis omitted, the SDK uses the sender's highest-balance veSCA position - amounts are raw on-chain units, so
1 SCA = 1_000_000_000
sCoin Operations
tx = builder.create_tx_block()
# Mint sCoin (from Market Coin)
scoin_idx = tx.mint_scoin(market_coin_idx=market_coin, coin_name="sui")
tx.transfer_objects([scoin_idx], client.wallet_address)
# Burn sCoin (get Market Coin back)
market_coin_idx = tx.burn_scoin(scoin_idx=scoin_input, coin_name="sui")
tx.transfer_objects([market_coin_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
Borrow Incentive
tx = builder.create_tx_block()
# Stake obligation
tx.stake_obligation(
obligation_id="0x...",
obligation_key="0x..."
)
# Claim rewards
reward_idx = tx.claim_borrow_incentive(
obligation_id="0x...",
obligation_key="0x...",
coin_name="sca"
)
tx.transfer_objects([reward_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
Referral Program
tx = builder.create_tx_block()
# Bind to a referrer (using referrer's veSCA key ID)
tx.bind_referral(referrer_vesca_key_id="0x...")
# Claim referral rewards
reward_idx = tx.claim_referral_revenue(
vesca_key_id="0x...", # Your veSCA key ID
coin_name="sui"
)
tx.transfer_objects([reward_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
Loyalty Program
tx = builder.create_tx_block()
# Claim loyalty rewards
reward_idx = tx.claim_loyalty_revenue(vesca_key_id="0x...")
tx.transfer_objects([reward_idx], client.wallet_address)
result = builder.sign_and_send_tx_block(tx)
Configuration
Environment Variables
Create a .env file:
PRIVATE_KEY=suiprivkey1... # or base64/hex format
NETWORK=mainnet
RPC_URL=https://fullnode.mainnet.sui.io:443
Then use from_env():
client = ScallopClient.from_env()
Supported Coins
| Coin | SDK Name | Decimals |
|---|---|---|
| SUI | sui |
9 |
| USDC (Native) | usdc |
6 |
| wUSDC (Wormhole) | wusdc |
6 |
| wUSDT (Wormhole) | wusdt |
6 |
| wETH (Wormhole) | weth |
8 |
| wBTC (Wormhole) | wbtc |
8 |
| wSOL (Wormhole) | wsol |
8 |
| wAPT (Wormhole) | wapt |
8 |
| CETUS | cetus |
9 |
| SCA | sca |
9 |
| DEEP | deep |
6 |
| FUD | fud |
5 |
| BLUB | blub |
2 |
| NS | ns |
6 |
| afSUI | afsui |
9 |
| haSUI | hasui |
9 |
| vSUI | vsui |
9 |
| HAEDAL | haedal |
9 |
| WAL | wal |
9 |
| haWAL | hawal |
9 |
| wWAL | wwal |
9 |
| USDY | usdy |
6 |
| FDUSD | fdusd |
6 |
| mUSD | musd |
9 |
| sbETH (Sui Bridge) | sbeth |
8 |
| sbUSDT (Sui Bridge) | sbusdt |
6 |
| sbwBTC (Sui Bridge) | sbwbtc |
8 |
| xBTC | xbtc |
8 |
| LOFI | lofi |
9 |
| suiUSDe | suiusde |
6 |
| zBTC | zwbtc |
8 |
Note: The supported coins list is fetched from Scallop API. Some coins may only support specific operations (lending, collateral, or borrowing). Check Scallop documentation for the latest availability.
API Reference
ScallopClient
Main entry point for SDK.
| Method | Description |
|---|---|
create_query() |
Create query interface |
create_builder() |
Create transaction builder |
ScallopQuery
| Method | Description |
|---|---|
get_obligation(obligation_id) |
Query one obligation |
list_user_obligations(address) |
List obligation IDs owned by a wallet |
get_coin_price(coin_name) |
Query one oracle-backed coin price |
get_coin_prices(coin_names) |
Query multiple oracle-backed coin prices |
get_market_pool(coin_name) |
Query one lending pool |
get_market_pools(coin_names=None) |
Query lending pools |
get_market_collateral(coin_name) |
Query one collateral pool |
get_market_collaterals(coin_names=None) |
Query collateral pools |
get_pool_address(coin_name) |
Query derived on-chain object addresses for one pool |
get_tvl(coin_names=None) |
Query aggregate TVL metrics |
get_lendings(address, coin_names=None) |
Query active lending positions |
get_user_portfolio(address) |
Query aggregated wallet portfolio |
get_spool(market_coin_name) |
Query one spool staking pool |
get_spools(market_coin_names=None) |
Query spool staking pools |
get_stake_accounts(market_coin_name, address) |
Query owned stake accounts for one spool |
get_all_stake_accounts(address) |
Query all owned stake accounts |
get_scoin_total_supply(coin_name) |
Query total sCoin supply |
get_scoin_amounts(coin_names=None, address=None) |
Query owned sCoin balances |
get_scoin_swap_rate(from_scoin, to_scoin) |
Query swap rate between sCoins |
get_vesca(vesca_key) |
Query one veSCA position |
get_vescas(address, exclude_empty=False) |
Query wallet veSCA positions |
get_vesca_treasury_info() |
Query aggregate veSCA treasury stats |
get_loyalty_program_info(vesca_key=None) |
Query loyalty reward pool and pending reward |
get_vesca_loyalty_program_info(vesca_key=None) |
Query veSCA loyalty pool and pending reward |
get_asset_oracles(coin_names=None) |
Query primary and secondary oracle routing |
get_price_update_policies() |
Query xOracle update policy rule objects |
ScallopTxBlock - Core Methods
| Method | Description |
|---|---|
supply(coin_input_idx, coin_name) |
Supply asset to lending pool |
withdraw(market_coin_idx, coin_name) |
Withdraw from lending pool |
borrow(obligation_id, obligation_key, amount, coin_name) |
Borrow from pool |
repay(obligation_id, coin_input_idx, coin_name) |
Repay borrowed amount |
deposit_collateral(obligation_id, coin_input_idx, coin_name) |
Deposit collateral |
withdraw_collateral(obligation_id, obligation_key, amount, coin_name) |
Withdraw collateral |
liquidate(obligation_id, repay_coin_idx, debt_coin_name, collateral_coin_name) |
Liquidate position → (TxResult, TxResult) |
borrow_flash_loan(amount, coin_name) |
Borrow flash loan → (TxResult, TxResult) |
repay_flash_loan(coin_idx, receipt_idx, coin_name) |
Repay flash loan (accepts int or TxResult) |
ScallopTxBlock - Quick Methods
| Method | Description |
|---|---|
supply_quick(amount, coin_name, sender) |
Auto coin selection supply |
withdraw_quick(amount, coin_name, sender) |
Auto coin selection withdraw |
borrow_quick(amount, coin_name, obligation_id, obligation_key) |
Auto price update borrow |
repay_quick(amount, coin_name, obligation_id, sender) |
Auto coin selection repay |
liquidate_quick(...) |
Auto coin selection liquidation |
lock_sca_quick(amount=None, lock_period_days=None, sender=None, vesca_key_id=None) |
Smart veSCA lifecycle helper for initial lock, extend, top-up, or expired renewal |
extend_lock_period_quick(lock_period_days, vesca_key_id=None, sender=None) |
Extend an active veSCA lock using sender lookup when needed |
extend_lock_amount_quick(sca_amount, sender, vesca_key_id=None) |
Auto-select SCA and add it to an active veSCA |
renew_expired_vesca_quick(sca_amount, lock_period_days, sender, vesca_key_id=None) |
Renew an expired veSCA with automatic SCA coin selection |
redeem_sca_quick(vesca_key_id=None, sender=None, transfer_sca=True) |
Redeem unlocked SCA and optionally auto-transfer it |
split_vesca_quick(split_amount, vesca_key_id, sender=None, transfer_vesca_key=True) |
Split a veSCA key with optional auto-transfer of the new key |
merge_vesca_quick(target_vesca_key_id, source_vesca_key_id) |
Merge veSCA keys with subscription safety and unlock alignment |
ObligationInfo
| Property | Type | Description |
|---|---|---|
obligation_id |
str |
Object ID |
debts |
List[DebtInfo] |
Debt positions |
collaterals |
List[CollateralInfo] |
Collateral positions |
risk_level |
Decimal |
Risk level (>= 1.0 = liquidatable) |
is_liquidatable |
bool |
Liquidation eligibility |
is_bad_debt |
bool |
Has debt but no collateral |
total_debt_usd |
Decimal |
Total debt in USD |
total_collateral_usd |
Decimal |
Total collateral in USD |
Development
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
make test
# Lint and format
make lint
make format
# Type checking
make typecheck
# Run all checks
make all
Mainnet Verification
All core operations have been verified on Sui mainnet (10/10 tests passed):
| # | Operation | Transaction | Status |
|---|---|---|---|
| 1 | Flash Loan (borrow + repay SUI) | F32f8cr... |
✅ |
| 2 | supply_quick (0.1 SUI) | F21Efd3... |
✅ |
| 3 | sCoin roundtrip (supply→mint→burn→withdraw) | BkLb4LB... |
✅ |
| 4 | Full lending cycle (Obligation + Collateral + Oracle + Borrow USDC) | BVWwpce... |
✅ |
| 5 | repay_quick (repay USDC) | C27xDCh... |
✅ |
| 6 | withdraw_collateral (with Oracle update) | 8MMpZyb... |
✅ |
| 7 | withdraw_quick (redeem Market Coin) | CXsck8H... |
✅ |
| 8 | supply + withdraw (non-quick) | AwxC6dM... |
✅ |
| 9 | transfer_objects (split + transfer) | 9cqVRxN... |
✅ |
| 10 | lock_sca (veSCA lock 10 SCA) | EfNSJTH... |
✅ |
Total gas: ~0.027 SUI
Notes
- Mainnet-first: Currently configured with mainnet addresses; testnet/devnet are placeholders
- Private Key Formats: Supports
suiprivkey1...(Bech32), Base64, and Hex. Use environment variables instead of hardcoding - Gas Fees: Transactions consume SUI as gas; ensure sufficient balance
- Oracle Updates: Call
update_asset_prices_quick()before borrow/liquidate operations
License
Apache License 2.0 - see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sui_scallop_sdk-0.3.0a1.tar.gz.
File metadata
- Download URL: sui_scallop_sdk-0.3.0a1.tar.gz
- Upload date:
- Size: 83.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
306a68dd80e43927e5dbd72438253b51c12072d4b35eda12e2d70fe49817ba0a
|
|
| MD5 |
0b26a369069fb21d3227fceb92bcffec
|
|
| BLAKE2b-256 |
0a988e74b5521b4fa363a179d3887f1f53cf6433c9f48de8a82ca9524e6ab7c2
|
Provenance
The following attestation bundles were made for sui_scallop_sdk-0.3.0a1.tar.gz:
Publisher:
publish.yml on scallop-io/sui-scallop-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sui_scallop_sdk-0.3.0a1.tar.gz -
Subject digest:
306a68dd80e43927e5dbd72438253b51c12072d4b35eda12e2d70fe49817ba0a - Sigstore transparency entry: 2256564404
- Sigstore integration time:
-
Permalink:
scallop-io/sui-scallop-sdk-python@508deedc28461ef6cb17d596d3bb8e9890abbf22 -
Branch / Tag:
refs/tags/v0.3.0a1 - Owner: https://github.com/scallop-io
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@508deedc28461ef6cb17d596d3bb8e9890abbf22 -
Trigger Event:
release
-
Statement type:
File details
Details for the file sui_scallop_sdk-0.3.0a1-py3-none-any.whl.
File metadata
- Download URL: sui_scallop_sdk-0.3.0a1-py3-none-any.whl
- Upload date:
- Size: 86.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d59b2c96be3b1d0df4233ab15f431bd2ce8df755a7dab3a35c66b869d77392a7
|
|
| MD5 |
5a60458b7058db92f18567e9211bea91
|
|
| BLAKE2b-256 |
8753d761815b425cbb2a598afe154e27319c87b2b99de8ba4c81566c99e75154
|
Provenance
The following attestation bundles were made for sui_scallop_sdk-0.3.0a1-py3-none-any.whl:
Publisher:
publish.yml on scallop-io/sui-scallop-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sui_scallop_sdk-0.3.0a1-py3-none-any.whl -
Subject digest:
d59b2c96be3b1d0df4233ab15f431bd2ce8df755a7dab3a35c66b869d77392a7 - Sigstore transparency entry: 2256564406
- Sigstore integration time:
-
Permalink:
scallop-io/sui-scallop-sdk-python@508deedc28461ef6cb17d596d3bb8e9890abbf22 -
Branch / Tag:
refs/tags/v0.3.0a1 - Owner: https://github.com/scallop-io
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@508deedc28461ef6cb17d596d3bb8e9890abbf22 -
Trigger Event:
release
-
Statement type: