agentsclimarketplace

Scallop error handling

Skill scallop-io/scallop-skills/skills/scallop-error-handling

Scallop SDK error handling and exception hierarchy. Use when user says "error", "exception", "error code", "handle errors", "ScallopError", "transaction failed", "debug", "troubleshoot", or asks about Scallop error handling, error codes, debugging failed transactions, or understanding SDK exceptions.From its SKILL.md

Install
npx -y skills add scallop-io/scallop-skills --skill scallop-error-handling

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

7.8 KB, as published. Nobody here has run it

Error Handling

Understand and handle errors from the Scallop Python SDK.

Exception Hierarchy

ScallopError (base)
├── ScallopConfigError          — Configuration/setup issues
├── ScallopQueryError           — Read operation failures
│   └── ObligationNotFoundError — Obligation doesn't exist on-chain
├── ScallopTransactionError     — Transaction execution failures
│   ├── ObligationLockedError   — Obligation staked in borrow incentive
│   ├── InsufficientBalanceError— Not enough coins
│   ├── ZeroAmountError         — Amount must be > 0
│   └── LiquidationError        — Liquidation failures
│       └── NotLiquidatableError— Position is healthy
├── UnsupportedCoinError        — Unknown coin name/type
├── OraclePriceError            — Price feed failure
└── NetworkError                — RPC connection failures

All exceptions inherit from ScallopError, so you can catch broadly or narrowly.

Import and Basic Usage

# These are in the public API (importable from sui_scallop_sdk directly):
from sui_scallop_sdk import (
    ScallopError,
    ScallopConfigError,
    ScallopQueryError,
    ScallopTransactionError,
    ObligationNotFoundError,
    UnsupportedCoinError,
)

# These must be imported from the exceptions module directly:
from sui_scallop_sdk.exceptions import (
    ObligationLockedError,
    InsufficientBalanceError,
    ZeroAmountError,
    OraclePriceError,
    LiquidationError,
    NotLiquidatableError,
    NetworkError,
    parse_scallop_error,
)

Exception Details

ScallopError (Base)

class ScallopError(Exception):
    message: str
    code: int | None = None

All SDK exceptions carry a message and optional numeric code.

ScallopConfigError

Raised when SDK configuration is invalid.

try:
    config = ScallopConfig(network="invalid")
except ScallopConfigError as e:
    print(f"Config error: {e}")

ObligationNotFoundError

try:
    obligation = query.get_obligation("0xnonexistent")
except ObligationNotFoundError as e:
    print(f"Not found: {e.obligation_id}")

Fields: obligation_id: str

ObligationLockedError

Raised when an obligation is staked in the borrow incentive program and you try to modify it without unstaking first.

try:
    tx.withdraw_collateral_quick(amount, "sui", obligation_id, obligation_key)
except ObligationLockedError as e:
    print(f"Obligation {e.obligation_id} is locked (code: {e.code})")
    # Solution: unstake obligation first
    # tx.unstake_obligation(obligation_id, obligation_key)

Fields: obligation_id: str, code: int = 770

InsufficientBalanceError

try:
    tx.supply_quick(1_000_000_000_000, "sui", wallet_address)
except InsufficientBalanceError as e:
    print(f"Need {e.required} {e.coin_name}, have {e.available}")

Fields: coin_name: str, required: int, available: int

UnsupportedCoinError

try:
    tx.supply_quick(100, "unknown_coin", wallet_address)
except UnsupportedCoinError as e:
    print(f"Unsupported: {e.coin}")

Fields: coin: str (stored from the coin_name_or_type constructor arg)

ZeroAmountError

try:
    tx.supply_quick(0, "sui", wallet_address)
except ZeroAmountError as e:
    print(f"Zero amount for operation: {e.operation}")

Fields: operation: str, code: int = 1537

OraclePriceError

try:
    tx.update_asset_prices_quick(["sui"])
except OraclePriceError as e:
    print(f"Oracle error for {e.coin_name}: {e}")

Fields: coin_name: str, details: str | None

NotLiquidatableError

try:
    tx.liquidate_quick(obligation_id, amount, "usdc", "sui", wallet_address)
except NotLiquidatableError as e:
    print(f"Position healthy — risk: {e.risk_level:.4f}")

Fields: obligation_id: str, risk_level: float

NetworkError

try:
    client = ScallopClient(rpc_url="https://bad-rpc.example.com")
except NetworkError as e:
    print(f"Cannot connect: {e.message} (URL: {e.rpc_url})")

Fields: message: str, rpc_url: str | None

Parsing Raw Errors

The SDK provides parse_scallop_error() to convert raw error strings (from RPC responses) into typed exceptions:

from sui_scallop_sdk.exceptions import parse_scallop_error

raw_error = "MoveAbort(0x...::lending::770)"

parsed = parse_scallop_error(raw_error)
if isinstance(parsed, ObligationLockedError):
    print("Obligation is locked in borrow incentive!")

This is useful when catching generic transaction failures and wanting to provide specific recovery suggestions.

On-Chain Error Codes

CodeExceptionMeaning
770ObligationLockedErrorObligation staked in borrow incentive
1537ZeroAmountErrorAmount must be greater than zero

The full error code reference is at Error Codes.

Error Handling Patterns

Broad Catch

try:
    result = builder.sign_and_send_tx_block(tx)
except ScallopError as e:
    print(f"Scallop error: {e}")
    if e.code:
        print(f"Error code: {e.code}")

Specific Recovery

from sui_scallop_sdk.exceptions import (
    InsufficientBalanceError,
    ObligationLockedError,
    OraclePriceError,
)

try:
    result = builder.sign_and_send_tx_block(tx)
except InsufficientBalanceError as e:
    print(f"Need more {e.coin_name}: have {e.available}, need {e.required}")
    # Maybe split the operation into smaller amounts
except ObligationLockedError:
    # Unstake, then retry
    tx2 = builder.create_tx_block()
    tx2.unstake_obligation(obligation_id, obligation_key)
    builder.sign_and_send_tx_block(tx2)
    # Now retry original operation
except OraclePriceError as e:
    print(f"Price feed down for {e.coin_name}, retrying...")
    # Maybe wait and retry, or use a different RPC
except ScallopError as e:
    print(f"Unexpected error: {e}")

Transaction with Full Error Handling

from sui_scallop_sdk import ScallopClient
from sui_scallop_sdk.exceptions import (
    ScallopError,
    InsufficientBalanceError,
    ObligationLockedError,
    OraclePriceError,
    NetworkError,
)

def safe_borrow(client, obligation_id, obligation_key, amount, coin_name):
    """Borrow with comprehensive error handling."""
    builder = client.create_builder()
    tx = builder.create_tx_block()

    try:
        borrowed = tx.borrow_quick(amount, coin_name, obligation_id, obligation_key)
        tx.transfer_objects([borrowed], client.wallet_address)
        result = builder.sign_and_send_tx_block(tx)

        if result.success:
            print(f"Borrowed {amount} {coin_name}: {result.digest}")
        else:
            print(f"TX failed: {result.error}")

        return result

    except InsufficientBalanceError as e:
        print(f"Insufficient balance: need {e.required}, have {e.available}")
    except ObligationLockedError:
        print("Obligation is locked — unstake from borrow incentive first")
    except OraclePriceError as e:
        print(f"Oracle unavailable for {e.coin_name}")
    except NetworkError as e:
        print(f"RPC error: {e.message}")
    except ScallopError as e:
        print(f"Error: {e}")

    return None

References

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.