> ## Documentation Index
> Fetch the complete documentation index at: https://docs.allium.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Sui JSON-RPC → gRPC Migration

> Sui raw datasets are moving from JSON-RPC-sourced to gRPC-sourced ingestion ahead of Sui's JSON-RPC deprecation. Most schemas are unchanged; a small number of fields change shape. Review before the cutover.

<Warning>
  **Action required by 19 August 2026.**

  Sui's raw datasets are migrating from JSON-RPC-sourced ingestion to gRPC-sourced ingestion, ahead of [Sui's deprecation of JSON-RPC](https://docs.sui.io/references/sui-api/json-rpc-format). **Table names, schemas, and the vast majority of columns are unchanged.** A few nested JSON fields change shape, so find the tables you query in the [table-by-table guide](#find-your-table) and update affected queries beforehand.
</Warning>

## Overview

Sui is deprecating its JSON-RPC interface in favor of gRPC. As a result, there are some changes to the `sui.raw` data.

## Cutover timeline

<Steps>
  <Step title="Mainnet cutover — 19 August 2026">
    `sui.raw.*` switches to the gRPC source. Update affected queries beforehand.
  </Step>
</Steps>

## Summary of Changes

<span id="find-your-table" />

Look up the table(s) you query. If a table isn't listed, **there are no changes**.

| Table you query              | Do you need to change anything?                                                                                                                       | Jump to                                    |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| `sui.raw.checkpoints`        | **No** — one field gains data (additive).                                                                                                             | [checkpoints](#checkpoints)                |
| `sui.raw.transactions`       | **Yes, if** you filter on `transaction_key` or read `transaction_value` sub-fields.                                                                   | [transactions](#transactions)              |
| `sui.raw.transaction_blocks` | **Yes, if** you read `transaction`, `effects`, or the flattened columns derived from them (`kind`, `message_version`, `tx_signatures`, `mutated`, …). | [transaction\_blocks](#transaction-blocks) |
| `sui.raw.events`             | **Yes, if** you read `parsed_json` fields.                                                                                                            | [events](#events)                          |
| `sui.raw.object_changes`     | **No** — gains a few rows (additive)                                                                                                                  | [object\_changes](#object-changes)         |
| `sui.raw.balance_changes`    | **No** — unchanged.                                                                                                                                   | —                                          |

***

### checkpoints

<span id="checkpoints" />

**No action required.** One field becomes richer:

* **`checkpoint_commitments`** — previously always an empty array (`[]`); now populated with the per-checkpoint commitment digest.

Everything else on `checkpoints` is unchanged.

***

### transactions

<span id="transactions" />

The `transaction` column holds a single Programmable Transaction Block (PTB) command, surfaced through `transaction_key` (the command name) and `transaction_value` (the command body). Both change shape.

**What changes**

1. **Command key casing** — command names are camelCase instead of PascalCase, so `transaction_key`'s value changes: `MoveCall` → `moveCall`, `SplitCoins` → `splitCoins`, `TransferObjects` → `transferObjects`, `MergeCoins` → `mergeCoins`, `MakeMoveVec` → `makeMoveVector`, `Publish` → `publish`, `Upgrade` → `upgrade`.
2. **Field naming inside the command** — `type_arguments` → `typeArguments`.
3. **Argument shape** — arguments carry an explicit `kind` and use different key names.

The `package`, `module`, and `function` values inside a command are **unchanged**.

**What to do**

* Make `transaction_key` filters case-insensitive: `LOWER(transaction_key) = 'movecall'` (instead of `= 'MoveCall'`). An exact `= 'MoveCall'` match will silently return **zero rows** after cutover.
* Update `transaction_value` path reads: `type_arguments` → `typeArguments`; adjust for the new argument encoding. `package` / `module` / `function` need no change.

<AccordionGroup>
  <Accordion title="transaction_value — old vs new shape" icon="table">
    **Old (JSON-RPC):**

    ```json theme={null}
    {
      "MoveCall": {
        "package": "0x94e8cb8df7796c7ea57f747f330ef61aedd8f48d48f7ac21bc975708a6ca6a1a",
        "module": "minter",
        "function": "wrap",
        "type_arguments": [
          "0x94e8...::reserve_ledger::RESERVE_LEDGER",
          "0x44f838...::usdsui::USDSUI"
        ],
        "arguments": [{ "Input": 0 }, { "Input": 1 }]
      }
    }
    ```

    **New (gRPC):**

    ```json theme={null}
    {
      "moveCall": {
        "package": "0x94e8cb8df7796c7ea57f747f330ef61aedd8f48d48f7ac21bc975708a6ca6a1a",
        "module": "minter",
        "function": "wrap",
        "typeArguments": [
          "0x94e8...::reserve_ledger::RESERVE_LEDGER",
          "0x44f838...::usdsui::USDSUI"
        ],
        "arguments": [
          { "input": 0, "kind": "INPUT" },
          { "input": 1, "kind": "INPUT" }
        ]
      }
    }
    ```

    The `package`, `module`, `function`, and type-argument **values are unchanged** — only the keys (`MoveCall`→`moveCall`, `type_arguments`→`typeArguments`) and the argument wrapper differ.
  </Accordion>

  <Accordion title="Example: updating a MoveCall filter" icon="code">
    **Before:**

    ```sql theme={null}
    SELECT *
    FROM sui.raw.transactions
    WHERE transaction_key = 'MoveCall'
      AND GET_PATH(transaction_value, 'package')  = '0x94e8...a6ca6a1a'
      AND GET_PATH(transaction_value, 'module')   = 'minter'
      AND GET_PATH(transaction_value, 'function') = 'wrap'
      AND GET_PATH(transaction_value, 'type_arguments[0]') = '0x94e8...::reserve_ledger::RESERVE_LEDGER'
    ```

    **After:**

    ```sql theme={null}
    SELECT *
    FROM sui.raw.transactions
    WHERE LOWER(transaction_key) = 'movecall'                              -- case-insensitive
      AND GET_PATH(transaction_value, 'package')  = '0x94e8...a6ca6a1a'    -- unchanged
      AND GET_PATH(transaction_value, 'module')   = 'minter'              -- unchanged
      AND GET_PATH(transaction_value, 'function') = 'wrap'                -- unchanged
      AND GET_PATH(transaction_value, 'typeArguments[0]') = '0x94e8...::reserve_ledger::RESERVE_LEDGER'  -- typeArguments
    ```

    <Warning>
      A `transaction_key = 'MoveCall'` filter matches **zero rows** after the change (the value becomes `'moveCall'`) — no error is raised. Audit any query that filters or joins on `transaction_key` or reads `transaction_value` sub-fields.
    </Warning>
  </Accordion>
</AccordionGroup>

***

## transaction\_blocks

<span id="transaction-blocks" />

This is the most affected table. The nested `transaction` and `effects` objects move to the native gRPC shape, and the top-level columns derived from them change accordingly.

**What to do**

* If you read the `transaction` VARIANT: `data.sender` → `sender`, `data.gasData` → `gasPayment`, `data.transaction.transactions` → `kind.programmableTransaction.commands` (plus the PTB command changes from [transactions](#transactions)).
* If you read the `effects` VARIANT: `status` flips to `{ "success": true/false }`; `executedEpoch` → `epoch`; `messageVersion` → `version`; and `mutated` / `created` / `sharedObjects` / `modifiedAtVersions` are derived from `changedObjects` + `unchangedConsensusObjects`.
* If you read the flattened top-level columns: check the [column table](#tb-columns) below — most values are unchanged, but `message_version`, `kind`, and `tx_signatures` change.

<AccordionGroup>
  <Accordion title="transaction envelope — old vs new shape" icon="table">
    **Old (JSON-RPC)** — sender, gas, and the PTB live under a `data` object, with `txSignatures` alongside:

    ```json theme={null}
    {
      "data": {
        "messageVersion": "v1",
        "sender": "0x7744ada2af3b150820b7bababee72b393e5c279f8d196064c3825b561ca7c7fa",
        "gasData": { "budget": "5808000", "owner": "0x7744...", "payment": [ ... ], "price": "404" },
        "transaction": {
          "kind": "ProgrammableTransaction",
          "inputs": [ ... ],
          "transactions": [ { "MoveCall": { ... } } ]
        }
      },
      "txSignatures": [ "AK7y..." ]
    }
    ```

    **New (gRPC)** — flattened: `sender`, `gasPayment`, `kind` at the top level, no `data` wrapper, and a `version`/`digest`/`bcs`/`expiration` set:

    ```json theme={null}
    {
      "bcs": { ... },
      "digest": "...",
      "version": 1,
      "sender": "0x7744ada2af3b150820b7bababee72b393e5c279f8d196064c3825b561ca7c7fa",
      "gasPayment": { "budget": "5808000", "objects": [ ... ], "owner": "0x7744...", "price": "404" },
      "kind": {
        "kind": "PROGRAMMABLE_TRANSACTION",
        "programmableTransaction": { "inputs": [ ... ], "commands": [ { "moveCall": { ... } } ] }
      }
    }
    ```

    Key path changes: `data.sender` → `sender`; `data.gasData` → `gasPayment` (and `payment` → `objects`); `data.transaction.kind` → `kind.kind` (value `ProgrammableTransaction` → `PROGRAMMABLE_TRANSACTION`); `data.transaction.transactions` → `kind.programmableTransaction.commands`; `data.messageVersion: "v1"` → top-level `version: 1`.
  </Accordion>

  <Accordion title="effects — key set and status shape" icon="table">
    **`status` (execution result):**

    ```json theme={null}
    // Old (JSON-RPC)                 // New (gRPC)
    { "status": "success" }           { "success": true }
    // failure case:
    { "status": "failure",            { "success": false,
      "error": "MoveAbort(...) ..." }   "error": { "kind": "MOVE_ABORT", "description": "MoveAbort(...) ...", ... } }
    ```

    **Top-level `effects` keys:**

    | JSON-RPC (old)                                                 | gRPC (new)                                                         | Notes                                                                                                                         |
    | -------------------------------------------------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
    | `executedEpoch`                                                | `epoch`                                                            | Renamed.                                                                                                                      |
    | `messageVersion` (`"v1"`)                                      | `version` (`1`)                                                    | Renamed; string → integer.                                                                                                    |
    | `mutated`, `created`, `sharedObjects`, `modifiedAtVersions`    | `changedObjects`, `unchangedConsensusObjects`                      | The per-type object arrays are consolidated into `changedObjects` (with input/output state) plus `unchangedConsensusObjects`. |
    | `gasObject`                                                    | `gasObject`                                                        | Present in both; the internal shape differs (gRPC exposes input/output state rather than `owner`/`reference`).                |
    | `status`                                                       | `status`                                                           | Shape flip (above).                                                                                                           |
    | `dependencies`, `eventsDigest`, `transactionDigest`, `gasUsed` | *(same)*                                                           | Unchanged.                                                                                                                    |
    | *(n/a)*                                                        | `bcs`, `digest`, `lamportVersion`, `unchangedLoadedRuntimeObjects` | New in gRPC — additional native fields with no JSON-RPC equivalent.                                                           |

    To reconstruct the old `mutated` / `created` / `sharedObjects` / `modifiedAtVersions` arrays, derive them from `changedObjects` (grouped by id-operation / input-output state) and `unchangedConsensusObjects`.
  </Accordion>

  <Accordion title="Flattened top-level columns — what changes" icon="table">
    <span id="tb-columns" />

    Several top-level columns are extracted from inside `transaction` / `effects`. They **remain populated** across the cutover (Allium reads both the old and new source paths), but a few carry different values or nested shapes for gRPC rows:

    | Column                                                | Change for gRPC rows                                                                                                                                                                        |
    | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `sender`                                              | Unchanged value (re-sourced from the new path). No action.                                                                                                                                  |
    | `inner_status`                                        | Unchanged value (`"success"` / `"failure"`), derived from the new `status` shape. No action.                                                                                                |
    | `executed_epoch`                                      | Unchanged value. No action.                                                                                                                                                                 |
    | `message_version` · `transaction_message_version`     | **Value changes**: JSON-RPC emitted `"v1"`; gRPC emits the numeric protocol version as text (e.g. `"2"`). Update any exact-string comparison.                                               |
    | `kind`                                                | **Value changes**: `"ProgrammableTransaction"` → `"PROGRAMMABLE_TRANSACTION"` (and equivalents for other kinds). Update any exact-string comparison.                                        |
    | `status` · `gas_object` · `gas_data` · `inputs`       | Populated, but the **nested JSON shape differs** (see the `effects` / `transaction` accordions above). Update any path expressions into these VARIANT columns.                              |
    | `mutated` · `shared_objects` · `modified_at_versions` | Populated from the native `changed_objects` / `unchanged_consensus_objects` structures instead of the JSON-RPC per-type arrays. The **element shape differs**; see the `effects` accordion. |
    | `tx_signatures`                                       | **Becomes `NULL`** for gRPC rows. The gRPC transaction block does not expose signatures; recover them from the BCS `raw_transaction` if needed.                                             |
  </Accordion>

  <Accordion title="raw_transaction / raw_effects — BCS envelope change" icon="table">
    These are the BCS-serialized transaction and effects. The gRPC and JSON-RPC APIs serialize them with **different BCS envelopes / type versions**, so the base64 bytes differ even though they decode to equivalent data.

    * `raw_transaction` — gRPC emits the inner `TransactionData` BCS; JSON-RPC emitted the full `SenderSignedData` envelope (transaction + signatures).
    * `raw_effects` — gRPC emits `TransactionEffects` in a newer BCS variant; the byte layout differs from the JSON-RPC form.

    If you decode these fields with a BCS library, use a decoder aligned to the Sui gRPC (`sui.rpc.v2`) types.
  </Accordion>
</AccordionGroup>

***

## events

<span id="events" />

Only `parsed_json` is affected, and only where an event's Move type contains certain field kinds. Scalar fields, addresses, and numeric-string fields are **unchanged**. The event's `bcs` field is byte-identical on both sources, so the underlying data is unchanged — only the `parsed_json` rendering differs.

**What changes**

1. **`vector<u8>` (byte vectors)** — a JSON array of byte integers under JSON-RPC, a base64 string under gRPC. Affected event types skew toward bridge / oracle events (e.g. Wormhole `TransferRedeemed`, Pyth `PriceFeedUpdateEvent`) that carry raw byte payloads.
2. **Single-field wrapper structs inside a vector** — flattened by gRPC (`[{ "name": "X" }]` → `[ "X" ]`).

**What to do**

* If you read a `vector<u8>` field, base64-decode the string to recover the bytes.
* Watch for flattened single-field wrapper structs.

<AccordionGroup>
  <Accordion title="vector<u8> — old vs new rendering" icon="table">
    A byte-vector field (e.g. a Wormhole emitter address, a Pyth price-feed id, a payload):

    ```json theme={null}
    // Old (JSON-RPC) — array of byte integers
    { "emitter_address": { "value": { "data": [0, 0, 0, 182, 246, 216, 106, 143, 152, 121, 169, ...] } } }

    // New (gRPC) — base64 string
    { "emitter_address": { "value": { "data": "AAAAtvbYao+YeanIf2Q3aNnvw4wdpuc=" } } }
    ```
  </Accordion>

  <Accordion title="single-field wrapper struct in a vector — old vs new" icon="table">
    ```json theme={null}
    // Old (JSON-RPC)
    { "permissions": [ { "name": "0x...::mod::PermissionsAdmin" }, { "name": "0x...::mod::ExtensionPermissionsAdmin" } ] }

    // New (gRPC) — the single-field struct is flattened to its value
    { "permissions": [ "0x...::mod::PermissionsAdmin", "0x...::mod::ExtensionPermissionsAdmin" ] }
    ```
  </Accordion>
</AccordionGroup>

***

## object\_changes

<span id="object-changes" />

**No action required.** The changes here are additive or preserved:

* **Additive rows** — a small number of additional object changes are surfaced: object-owned (dynamic-field) mutations, plus rare `published` rows that now carry a populated `object_id` / `object_type` where they were previously null. Row counts may be slightly higher on affected transactions (roughly \~1 in 100k rows); `object_changes_count` on `transaction_blocks` reflects this. No existing row's values change.
* **`owner` — preserved.** At the gRPC source, consensus-owned objects report `{ "AddressOwner": "0x…" }` (dropping the ownership variant and its `start_version`). Allium restores the JSON-RPC form `{ "ConsensusAddressOwner": { "owner": "0x…", "start_version": … } }` during ingestion. The `owner` field is unchanged for all ownership types (`AddressOwner`, `ObjectOwner`, `Shared`, `ConsensusAddressOwner`, `Immutable`).

***

## balance\_changes

`sui.raw.balance_changes` is **unchanged** — no action required.

## Support

If this migration impacts your workflows or you need help, reach out to [support@allium.so](mailto:support@allium.so) or your account team.
