Obligation Manager
Query, monitor, and manage Scallop lending obligations.
Overview
An obligation is a user's lending position containing:
- Collaterals: Assets deposited as collateral
- Debts: Borrowed amounts
- Risk Metrics: Health factor, borrow capacity
Query Obligations
List User Obligations
query = client.create_query()
# List all obligation IDs for an address (returns list[str])
obligation_ids = query.list_user_obligations(wallet_address)
for ob_id in obligation_ids:
print(f"Obligation ID: {ob_id}")
Get Obligation Details
# Basic obligation data (ObligationInfo)
obligation = query.get_obligation(obligation_id)
print(f"Collaterals: {len(obligation.collaterals)} positions")
print(f"Debts: {len(obligation.debts)} positions")
print(f"Risk Level: {obligation.risk_level}")
Get Obligation with Prices
# Includes USD values and risk metrics
obligation = query.get_obligation_with_prices(obligation_id)
print(f"Total Collateral USD: ${obligation.total_collateral_usd:,.2f}")
print(f"Total Debt USD: ${obligation.total_debt_usd:,.2f}")
print(f"Risk Level: {obligation.risk_level:.2f}")
print(f"Is Liquidatable: {obligation.is_liquidatable}")
Risk Assessment
Risk Level Calculation
risk_level = total_debt_value / (total_collateral_value * weighted_collateral_factor)
Risk Thresholds
| Risk Level | Status | Description |
|---|---|---|
| < 0.70 | 🟢 Safe | Healthy position |
| 0.70 - 0.90 | 🟡 Warning | Consider adding collateral |
| 0.90 - 1.00 | 🔴 Danger | High liquidation risk |
| >= 1.00 | ⚫ Liquidatable | Can be liquidated |
Risk Check Function
def assess_risk(obligation):
risk = obligation.risk_level
if risk < 0.7:
return "🟢 Safe", "Position is healthy"
elif risk < 0.9:
return "🟡 Warning", "Consider adding collateral or repaying debt"
elif risk < 1.0:
return "🔴 Danger", "High liquidation risk! Take action immediately"
else:
return "⚫ Liquidatable", "Position can be liquidated!"
Only
1.0is enforced by the protocol; the other bands are operational guidance. Note that 0.90 is roughly a 10% collateral price drop from liquidation, so alert well below the danger band. See risk-calculations.md.
Obligation Status Report
Generate a comprehensive status report:
def generate_report(query, obligation_id):
ob = query.get_obligation_with_prices(obligation_id)
report = f"""
## Obligation Status: {obligation_id[:8]}...{obligation_id[-4:]}
### Summary
| Metric | Value | Status |
|--------|-------|--------|
| Total Collateral | ${ob.total_collateral_usd:,.2f} | - |
| Total Debt | ${ob.total_debt_usd:,.2f} | - |
| Risk Level | {ob.risk_level:.2f} | {get_risk_emoji(ob.risk_level)} |
| Liquidatable | {ob.is_liquidatable} | - |
### Collaterals
| Asset | Amount | Value USD |
|-------|--------|-----------|
"""
for c in ob.collaterals:
report += f"| {c.coin_symbol} | {c.amount_coin:,.4f} | ${c.value_usd:,.2f} |\n"
report += "\n### Debts\n| Asset | Amount | Value USD |\n|-------|--------|-----------|\\n"
for d in ob.debts:
report += f"| {d.coin_symbol} | {d.amount_coin:,.4f} | ${d.value_usd:,.2f} |\n"
return report
Collateral Management
Deposit Collateral
tx = builder.create_tx_block()
# Deposit 5 SUI as collateral
tx.deposit_collateral_quick(
amount=5_000_000_000,
coin_name="sui",
obligation_id=obligation_id,
sender=wallet_address
)
result = builder.sign_and_send_tx_block(tx)
Withdraw Collateral
# Check if withdrawal is safe first
ob = query.get_obligation_with_prices(obligation_id)
withdrawal_amount = 2_000_000_000 # 2 SUI
# Calculate new risk after withdrawal
new_collateral = ob.total_collateral_usd - (withdrawal_amount * sui_price / 1e9)
new_risk = ob.total_debt_usd / (new_collateral * avg_factor)
if new_risk < 0.9:
tx = builder.create_tx_block()
withdrawn = tx.withdraw_collateral_quick(
amount=withdrawal_amount,
coin_name="sui",
obligation_id=obligation_id,
obligation_key=obligation_key,
)
tx.transfer_objects([withdrawn], wallet_address)
result = builder.sign_and_send_tx_block(tx)
else:
print("Warning: Withdrawal would put position at risk!")
Always size a withdrawal against projected risk, not current risk. Treat
0.9as a strict ceiling rather than a target, and noteavg_factoris a simplification — withdrawing an entire asset shifts the weighted collateral factor itself. See collateral-guide.md.
Monitoring Script
Automated position monitoring:
import time
from sui_scallop_sdk import ScallopClient
def monitor_positions(client, obligations, alert_threshold=0.8):
query = client.create_query()
while True:
for ob_id in obligations:
ob = query.get_obligation_with_prices(ob_id)
if ob.risk_level >= alert_threshold:
print(f"⚠️ ALERT: Position {ob_id[:8]} at risk!")
print(f" Risk Level: {ob.risk_level:.2f}")
print(f" Collateral: ${ob.total_collateral_usd:,.2f}")
print(f" Debt: ${ob.total_debt_usd:,.2f}")
# Optional: auto-add collateral
# auto_add_collateral(client, ob_id)
time.sleep(60) # Check every minute
# Run monitor
client = ScallopClient(secret_key="...", network="mainnet")
obligations = ["0x123...", "0x456..."]
monitor_positions(client, obligations)
Obligation Locking
Obligations are locked during certain operations. Unlocking is automatic with obligation_key — some operations like borrow_quick and withdraw_collateral_quick handle locking/unlocking internally.
Multi-Obligation Strategy
For users with multiple obligations:
def optimize_positions(query, obligations):
positions = []
for ob_id in obligations:
ob = query.get_obligation_with_prices(ob_id)
positions.append({
'id': ob_id,
'risk': ob.risk_level,
'collateral': ob.total_collateral_usd,
'debt': ob.total_debt_usd
})
# Sort by risk (highest first)
positions.sort(key=lambda x: x['risk'], reverse=True)
# Recommendations
for pos in positions:
if pos['risk'] > 0.9:
print(f"🔴 {pos['id'][:8]}: URGENT - Add collateral or repay debt")
elif pos['risk'] > 0.7:
print(f"🟡 {pos['id'][:8]}: Consider rebalancing")
else:
print(f"🟢 {pos['id'][:8]}: Healthy")
References
- Risk Calculations - Risk level formulas
- Collateral Guide - Collateral management
- Error Codes - Error reference