Skip to main content

Python SDK for Scallop Lending Protocol on Sui

Project description

Scallop Python SDK

PyPI version CI Python License

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_id is optional for lock_sca_quick, extend_lock_period_quick, extend_lock_amount_quick, renew_expired_vesca_quick, and redeem_sca_quick
  • when vesca_key_id is 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

  1. Mainnet-first: Currently configured with mainnet addresses; testnet/devnet are placeholders
  2. Private Key Formats: Supports suiprivkey1... (Bech32), Base64, and Hex. Use environment variables instead of hardcoding
  3. Gas Fees: Transactions consume SUI as gas; ensure sufficient balance
  4. Oracle Updates: Call update_asset_prices_quick() before borrow/liquidate operations

License

Apache License 2.0 - see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sui_scallop_sdk-0.3.0a1.tar.gz (83.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sui_scallop_sdk-0.3.0a1-py3-none-any.whl (86.1 kB view details)

Uploaded Python 3

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

Hashes for sui_scallop_sdk-0.3.0a1.tar.gz
Algorithm Hash digest
SHA256 306a68dd80e43927e5dbd72438253b51c12072d4b35eda12e2d70fe49817ba0a
MD5 0b26a369069fb21d3227fceb92bcffec
BLAKE2b-256 0a988e74b5521b4fa363a179d3887f1f53cf6433c9f48de8a82ca9524e6ab7c2

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sui_scallop_sdk-0.3.0a1-py3-none-any.whl.

File metadata

File hashes

Hashes for sui_scallop_sdk-0.3.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 d59b2c96be3b1d0df4233ab15f431bd2ce8df755a7dab3a35c66b869d77392a7
MD5 5a60458b7058db92f18567e9211bea91
BLAKE2b-256 8753d761815b425cbb2a598afe154e27319c87b2b99de8ba4c81566c99e75154

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page