# Scallop Rpc Client

> Direct Sui RPC access via SuiRpcClient for low-level blockchain queries. Use when user says "RPC", "JSON-RPC", "get object", "dynamic fields", "execute transaction", "raw RPC", "SuiRpcClient", "async RPC", or asks about direct Sui blockchain access, querying objects, dynamic fields, or executing raw transactions outside of Scallop-specific operations.

- Skill: `scallop-io/scallop-rpc-client` (Agent Skill)
- Install (CLI): `npx skillmds@latest add scallop-io/scallop-rpc-client`
- Raw SKILL.md: https://api.skillmd.com/api/skills/scallop-io/scallop-rpc-client/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: scallop-io (https://skillmd.com/u/scallop-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/scallop-io/scallop-rpc-client

---


# Sui RPC Client

Direct Sui JSON-RPC access for low-level blockchain queries and transaction execution.

## Overview

The SDK includes `SuiRpcClient` (sync) and `AsyncSuiRpcClient` (async) for direct Sui blockchain interaction. These are used internally by `ScallopQuery` and `ScallopBuilder`, but you can also use them directly for custom queries.

## Quick Start

```python
from sui_scallop_sdk import SuiRpcClient

# Standalone
rpc = SuiRpcClient("https://fullnode.mainnet.sui.io:443", timeout=30.0)

# Or from an existing ScallopClient
client = ScallopClient(network="mainnet")
rpc = client.rpc_client
```

## SuiRpcClient Methods

### Object Queries

```python
# Get single object
obj = rpc.get_object(
    "0xOBJECT_ID",
    options={"showContent": True, "showType": True, "showOwner": True},
)
print(obj["data"]["content"])

# Get multiple objects in one call
objects = rpc.get_objects(
    ["0xOBJ_1", "0xOBJ_2", "0xOBJ_3"],
    options={"showContent": True},
)

# Get objects owned by address
owned = rpc.get_owned_objects(
    owner="0xADDRESS",
    object_type="0x2::coin::Coin<0x2::sui::SUI>",  # Optional filter
    cursor=None,   # For pagination
    limit=50,
)
for item in owned["data"]:
    print(item["data"]["objectId"])
```

### Coin Queries

```python
# Get coins of specific type
coins = rpc.get_coins(
    owner="0xADDRESS",
    coin_type="0x2::sui::SUI",  # Optional
    limit=50,
)
for coin in coins["data"]:
    print(f"ID: {coin['coinObjectId']}, Balance: {coin['balance']}")

# Get ALL coins (any type)
all_coins = rpc.get_all_coins(owner="0xADDRESS", limit=50)

# Get aggregated balance
balance = rpc.get_balance(
    owner="0xADDRESS",
    coin_type="0x2::sui::SUI",
)
print(f"Total: {balance['totalBalance']}")

# Get all balances across all coin types
balances = rpc.get_all_balances(owner="0xADDRESS")
for b in balances:
    print(f"{b['coinType']}: {b['totalBalance']}")
```

### Dynamic Fields

Dynamic fields are on-chain key-value pairs attached to objects. Scallop uses them extensively for obligation data storage.

```python
# List dynamic fields of a parent object
fields = rpc.get_dynamic_fields(
    parent_id="0xPARENT_OBJECT",
    cursor=None,
    limit=50,
)
for field in fields["data"]:
    print(f"Name: {field['name']}, Type: {field['objectType']}")

# Get specific dynamic field by name
field_obj = rpc.get_dynamic_field_object(
    parent_id="0xPARENT_OBJECT",
    name={"type": "address", "value": "0x123..."},
)
```

### Transaction Execution

```python
import base64

# Dry run (simulate)
dry_result = rpc.dry_run_transaction(
    tx_bytes=base64.b64encode(tx_bytes).decode(),
)
print(f"Gas: {dry_result['effects']['gasUsed']}")

# Execute signed transaction
exec_result = rpc.execute_transaction(
    tx_bytes=base64.b64encode(tx_bytes).decode(),
    signatures=["base64_signature_string"],
    options={
        "showEffects": True,
        "showEvents": True,
        "showObjectChanges": True,
    },
)
print(f"Digest: {exec_result['digest']}")
```

### Utility Methods

```python
# Get current gas price
gas_price = rpc.get_reference_gas_price()
print(f"Gas price: {gas_price} MIST")

# Get chain identifier
chain_id = rpc.get_chain_identifier()
print(f"Chain: {chain_id}")
```

## Context Manager

```python
with SuiRpcClient("https://fullnode.mainnet.sui.io:443") as rpc:
    obj = rpc.get_object("0x...")
# Connection automatically closed
```

Or manually:

```python
rpc = SuiRpcClient("https://fullnode.mainnet.sui.io:443")
try:
    # ... use rpc
finally:
    rpc.close()
```

## AsyncSuiRpcClient

Same API as `SuiRpcClient`, but all methods are `async`:

```python
from sui_scallop_sdk.sui_rpc import AsyncSuiRpcClient  # Not in __all__, import directly
import asyncio

async def main():
    async with AsyncSuiRpcClient("https://fullnode.mainnet.sui.io:443") as rpc:
        # All methods are awaitable
        obj = await rpc.get_object("0xOBJECT_ID")
        balance = await rpc.get_balance("0xADDRESS")
        coins = await rpc.get_coins("0xADDRESS")

        # Parallel queries
        results = await asyncio.gather(
            rpc.get_balance("0xADDR1"),
            rpc.get_balance("0xADDR2"),
            rpc.get_balance("0xADDR3"),
        )

asyncio.run(main())
```

### Available Async Methods

| Method | Signature |
|--------|-----------|
| `get_object` | `async (object_id, options?) -> dict` |
| `get_coins` | `async (owner, coin_type?, cursor?, limit?) -> dict` |
| `get_balance` | `async (owner, coin_type?) -> dict` |
| `close` | `async () -> None` |

The async client currently supports a subset of methods. For full coverage, use the sync client.

## Error Handling

```python
from sui_scallop_sdk import SuiRpcError

try:
    obj = rpc.get_object("0xinvalid")
except SuiRpcError as e:
    print(f"RPC error {e.code}: {e.message}")
```

`SuiRpcError` has:
- `code: int` — JSON-RPC error code
- `message: str` — Error description

## Pagination Pattern

Many RPC methods return paginated results:

```python
all_coins = []
cursor = None

while True:
    result = rpc.get_coins(
        owner=address,
        coin_type=coin_type,
        cursor=cursor,
        limit=50,
    )
    all_coins.extend(result["data"])

    if not result.get("hasNextPage"):
        break
    cursor = result.get("nextCursor")

print(f"Found {len(all_coins)} coins")
```

## Complete Example: Inspect Obligation On-Chain

```python
from sui_scallop_sdk import ScallopClient, SuiRpcClient

client = ScallopClient(network="mainnet")
rpc = client.rpc_client

obligation_id = "0x..."

# Get raw obligation object
obj = rpc.get_object(obligation_id, options={"showContent": True, "showType": True})
content = obj["data"]["content"]
print(f"Type: {obj['data']['type']}")
print(f"Fields: {list(content['fields'].keys())}")

# Explore dynamic fields (debts, collaterals stored here)
fields = rpc.get_dynamic_fields(obligation_id)
for f in fields["data"]:
    print(f"  Field: {f['name']['value']} -> {f['objectType']}")

    # Read individual field
    detail = rpc.get_dynamic_field_object(obligation_id, f["name"])
    print(f"    Content: {detail['data']['content']['fields']}")
```

## sui-kit (TypeScript) — Higher-Level Building Blocks

The Python `SuiRpcClient` above is the low-level surface. On the TypeScript side, [`sui-kit`](../../../sui-kit/) (which the TS SDK builds on) ships three companion classes. All of them are re-exported from the package root — `@scallop-io/sui-kit` only exports `.`, so always import from the root, not from internal subpaths.

```typescript
import {
  SuiKit,
  SuiTxBlock,
  SuiAccountManager,
  MultiSigClient,
} from '@scallop-io/sui-kit';
```

### `MultiSigClient` — Sui Multisig Helpers

Wraps publickey collection, threshold configuration and signature combination for multisig wallets. See [sui-kit/src/libs/multiSig/client.ts](../../../sui-kit/src/libs/multiSig/client.ts) for the implementation.

```typescript
import { MultiSigClient } from '@scallop-io/sui-kit';

// Option 1: from already-decoded PublicKey instances
const multiSig = new MultiSigClient(
  [
    { publicKey: pkA, weight: 1 },
    { publicKey: pkB, weight: 1 },
    { publicKey: pkC, weight: 1 },
  ],
  2, // threshold
);

// Option 2: from raw base64-encoded ed25519 pubkeys
const multiSig2 = MultiSigClient.fromRawEd25519PublicKeys(
  [pkA_base64, pkB_base64, pkC_base64],
  [1, 1, 1],
  2,
);

const address = multiSig.multiSigAddress();                  // derived multisig address
const combined = multiSig.combinePartialSigs([sigA, sigB]);  // ready to submit
```

Use this when:
- Treasury or operations wallets must co-sign Scallop transactions.
- A keeper bot's signing key needs an admin override path.

### `SuiAccountManager` — Keypair Lifecycle

[sui-kit/src/libs/suiAccountManager/](../../../sui-kit/src/libs/suiAccountManager/) is a thin layer on top of mnemonic/keypair generation, derivation paths and signing. It's also the source the TS SDK uses internally — drop down to it when you need account features not exposed by the SDK (e.g. multiple derivation paths from one seed).

See [crypto-keys](../scallop-crypto-keys/SKILL.md) for the Python equivalent.

### `SuiTxBlock` — Transaction Composition

`SuiTxBlock` wraps `@mysten/sui` `Transaction` with ergonomic helpers (`splitSUIFromGas`, `transferCoinToMany`, `mergeCoins`, `moveCall` with named args). `ScallopBuilder` extends it — drop down to plain `SuiTxBlock` when you're composing a PTB that mixes Scallop calls with arbitrary `moveCall`s and want the same fluent API.

```typescript
import { SuiKit, SuiTxBlock } from '@scallop-io/sui-kit';

const suiKit = new SuiKit({ mnemonics: '...' });
const tx = new SuiTxBlock();

tx.splitSUIFromGas([1_000_000_000]);
tx.moveCall(`${scallopPkg}::user::supply`, [/* args */], [coinType]);

// suiKit.currentAddress is a getter (property), not a function.
tx.transferObjects([/* ... */], suiKit.currentAddress);

await suiKit.signAndSendTxn(tx);
```

For Scallop-specific composition patterns see [advanced-transactions](../scallop-advanced-transactions/SKILL.md).

## References

- [Sui Basics](../../references/sui-basics.md) - Sui blockchain fundamentals
- [Addresses](../../references/addresses.md) - Protocol contract addresses
- [Crypto Keys Skill](../scallop-crypto-keys/SKILL.md) - Python keypair lifecycle
- [Advanced Transactions](../scallop-advanced-transactions/SKILL.md) - PTB composition patterns

