Python SDK
The Coalesce Finance Python SDK for building applications and scripts that interact with the permissioned lending protocol.
Installation
pip install coalescefi-sdk
Or with development dependencies:
pip install coalescefi-sdk[dev]
Requirements
- Python 3.10+
solana-py>= 0.35.0solders>= 0.21.0
Quick Start
from solana.rpc.async_api import AsyncClient
from solders.pubkey import Pubkey
from coalescefi_sdk import (
configure_sdk,
find_market_pda,
find_lender_position_pda,
fetch_market,
create_deposit_instruction,
)
# Configure the SDK
configure_sdk(network="devnet")
# Or with explicit program ID
configure_sdk(program_id=Pubkey.from_string("CoaLfi..."))
# Derive PDAs
borrower = Pubkey.from_string("Borrower...")
market_pda, market_bump = find_market_pda(borrower, market_nonce=1)
lender_pda, lender_bump = find_lender_position_pda(market_pda, lender_pubkey)
# Fetch account data
async def main():
connection = AsyncClient("https://api.devnet.solana.com")
market = await fetch_market(connection, market_pda)
if market:
print(f"Total deposited: {market.total_deposited}")
print(f"Interest rate: {market.annual_interest_bps} bps")
asyncio.run(main())
Configuration
Network-based Configuration
from coalescefi_sdk import configure_sdk, NetworkName
# Use predefined network
configure_sdk(network="mainnet") # or "devnet", "localnet"
# With custom RPC
configure_sdk(
network="mainnet",
rpc_url="https://my-rpc.example.com"
)
Explicit Program ID
from solders.pubkey import Pubkey
from coalescefi_sdk import configure_sdk
configure_sdk(
program_id=Pubkey.from_string("CoaLfi...")
)
Environment Variables
The SDK also reads from environment variables:
export COALESCEFI_PROGRAM_ID="CoaLfi..."
export COALESCEFI_NETWORK="devnet"
PDA Derivation
All PDA functions return a tuple of (Pubkey, bump):
from coalescefi_sdk import (
find_protocol_config_pda,
find_market_pda,
find_market_authority_pda,
find_vault_pda,
find_lender_position_pda,
find_borrower_whitelist_pda,
find_blacklist_check_pda,
derive_market_pdas,
)
# Protocol config (singleton)
config_pda, config_bump = find_protocol_config_pda()
# Market PDAs
market_pda, market_bump = find_market_pda(borrower, market_nonce=1)
authority_pda, authority_bump = find_market_authority_pda(market_pda)
vault_pda, vault_bump = find_vault_pda(market_pda)
# Lender position
lender_pda, lender_bump = find_lender_position_pda(market_pda, lender)
# Borrower whitelist
whitelist_pda, whitelist_bump = find_borrower_whitelist_pda(borrower)
# Derive all market-related PDAs at once
market_pdas = derive_market_pdas(borrower, market_nonce=1)
print(market_pdas.market)
print(market_pdas.market_authority)
print(market_pdas.vault)
Account Fetching
The SDK provides async fetchers with built-in retry logic:
from solana.rpc.async_api import AsyncClient
from coalescefi_sdk import (
fetch_protocol_config,
fetch_market,
fetch_lender_position,
fetch_borrower_whitelist,
RetryConfig,
)
async def fetch_accounts():
connection = AsyncClient("https://api.devnet.solana.com")
# With default retry config (3 retries, exponential backoff)
market = await fetch_market(connection, market_pda)
# With custom retry config
custom_retry = RetryConfig(
max_retries=5,
base_delay_ms=500,
max_delay_ms=5000
)
config = await fetch_protocol_config(
connection,
config_pda,
retry_config=custom_retry
)
# Returns None if account doesn't exist
position = await fetch_lender_position(connection, lender_pda)
if position is None:
print("Position not found")
Account Decoding
For manual decoding of raw account data:
from coalescefi_sdk import (
decode_protocol_config,
decode_market,
decode_lender_position,
decode_borrower_whitelist,
decode_account, # Auto-detects type
)
# Decode specific account type
market = decode_market(account_data)
print(f"Borrower: {market.borrower}")
print(f"Annual interest: {market.annual_interest_bps} bps")
print(f"Maturity: {market.maturity_timestamp}")
# Auto-detect and decode
account = decode_account(raw_data)
if isinstance(account, Market):
print("It's a market!")
Instruction Building
Build instructions for all protocol operations:
from coalescefi_sdk import (
create_deposit_instruction,
create_borrow_instruction,
create_repay_instruction,
create_withdraw_instruction,
)
# Deposit instruction
deposit_ix = create_deposit_instruction(
accounts={
"market": market_pda,
"lender": lender_pubkey,
"lender_token_account": lender_ata,
"vault": vault_pda,
"lender_position": lender_position_pda,
"blacklist_check": blacklist_check_pda,
"protocol_config": config_pda,
"mint": usdc_mint,
"token_program": TOKEN_PROGRAM_ID,
"system_program": SYSTEM_PROGRAM_ID,
},
args={"amount": 1_000_000}, # 1 USDC (6 decimals)
)
Available Instructions
| Function | Description |
|---|---|
create_initialize_protocol_instruction | Initialize protocol config |
create_set_fee_config_instruction | Update fee settings |
create_create_market_instruction | Create a new lending market |
create_deposit_instruction | Deposit tokens to a market |
create_borrow_instruction | Borrow from a market |
create_repay_instruction | Repay borrowed amount |
create_repay_interest_instruction | Repay accrued interest |
create_withdraw_instruction | Withdraw deposited tokens |
create_collect_fees_instruction | Collect protocol fees |
create_re_settle_instruction | Re-settle after maturity |
create_close_lender_position_instruction | Close empty position |
create_withdraw_excess_instruction | Withdraw excess funds |
create_set_borrower_whitelist_instruction | Manage whitelist |
create_set_pause_instruction | Pause/unpause protocol |
create_set_blacklist_mode_instruction | Configure blacklist |
create_set_admin_instruction | Transfer admin role |
create_set_whitelist_manager_instruction | Set whitelist manager |
Error Handling
from coalescefi_sdk import (
CoalescefiError,
CoalescefiErrorCode,
parse_coalescefi_error,
is_user_recoverable_error,
get_error_recovery_action,
)
try:
# ... transaction execution
pass
except Exception as e:
error = parse_coalescefi_error(e)
if error:
print(f"Error code: {error.code.name}")
print(f"Message: {error.message}")
if is_user_recoverable_error(error.code):
action = get_error_recovery_action(error.code)
print(f"Recovery action: {action}")
Error Categories
from coalescefi_sdk import (
get_error_category,
get_error_severity,
ErrorCategory,
ErrorSeverity,
)
category = get_error_category(CoalescefiErrorCode.InsufficientBalance)
# ErrorCategory.Balance
severity = get_error_severity(CoalescefiErrorCode.Unauthorized)
# ErrorSeverity.Error
Idempotency Support
Prevent duplicate transactions with the idempotency manager:
from coalescefi_sdk import (
IdempotencyManager,
generate_idempotency_key,
)
manager = IdempotencyManager()
# Generate deterministic key for operation
key = generate_idempotency_key("deposit", {
"market": str(market_pda),
"amount": str(amount),
"lender": str(lender),
})
# Execute with idempotency protection
async def safe_deposit():
result = await manager.execute_once(
connection,
key,
lambda: execute_deposit_transaction(),
)
return result
Type Annotations
The SDK is fully typed for IDE support:
from coalescefi_sdk import (
ProtocolConfig,
Market,
LenderPosition,
BorrowerWhitelist,
)
def process_market(market: Market) -> None:
# Full type hints available
borrower: Pubkey = market.borrower
rate: int = market.annual_interest_bps
maturity: int = market.maturity_timestamp
Constants
from coalescefi_sdk import (
# Mathematical constants
WAD, # 10^18 - precision factor
BPS, # 10000 - basis points denominator
SECONDS_PER_YEAR,
# Protocol limits
MAX_ANNUAL_INTEREST_BPS, # 10000 (100%)
MAX_FEE_RATE_BPS, # 10000 (100%)
USDC_DECIMALS, # 6
# Account sizes
PROTOCOL_CONFIG_SIZE,
MARKET_SIZE,
LENDER_POSITION_SIZE,
BORROWER_WHITELIST_SIZE,
# Seeds
SEED_PROTOCOL_CONFIG,
SEED_MARKET,
SEED_VAULT,
)
Testing
import pytest
from coalescefi_sdk import configure_sdk, reset_sdk_config
@pytest.fixture(autouse=True)
def reset_config():
"""Reset SDK config between tests."""
yield
reset_sdk_config()
def test_pda_derivation():
configure_sdk(network="localnet")
pda, bump = find_market_pda(borrower, 1)
assert bump > 0
Next Steps
- TypeScript SDK - If you need browser support
- Rust SDK - For on-chain programs
- SDK Overview - Protocol reference and shared-core
- Error Codes - Error codes reference