---
title: "RPC Protocol"
description: "JSON-RPC method contract, validation, and error handling."
url: "https://sigilry.org/concepts/rpc-protocol"
---

Sigilry uses JSON-RPC 2.0 for dApp to wallet communication. Methods and schemas are defined in OpenRPC and validated with Zod at runtime.

## Request and response shapes

```ts
import type { JsonRpcRequest, JsonRpcResponse } from "@sigilry/dapp/messages";

const request: JsonRpcRequest = {
  jsonrpc: "2.0",
  id: "request-id",
  method: "status",
};

const success: JsonRpcResponse = {
  jsonrpc: "2.0",
  id: "request-id",
  result: {
    /* method result */
  },
};

const failure: JsonRpcResponse = {
  jsonrpc: "2.0",
  id: "request-id",
  error: { code: -32601, message: "Method not found" },
};
```

## Methods

| Method                  | Params                       | Result                                 |
| ----------------------- | ---------------------------- | -------------------------------------- |
| `status`                | none                         | `StatusEvent`                          |
| `connect`               | none                         | `ConnectResult`                        |
| `disconnect`            | none                         | `null`                                 |
| `isConnected`           | none                         | `ConnectResult`                        |
| `getActiveNetwork`      | none                         | `Network`                              |
| `listAccounts`          | none                         | `Wallet[]`                             |
| `getPrimaryAccount`     | none                         | `Wallet`                               |
| `prepareExecute`        | `JsPrepareSubmissionRequest` | `null`                                 |
| `prepareExecuteAndWait` | `JsPrepareSubmissionRequest` | `{ tx: TxChangedExecutedEvent }`       |
| `signMessage`           | `{ message: string }`        | `SignMessageResult`                    |
| `ledgerApi`             | `LedgerApiRequest`           | `Record<string, unknown> \| unknown[]` |

`SignMessageResult` always carries `signature` and may carry optional `signedBy`, `publicKey`, `signingAlgorithmSpec`, `format`, and `encoding` fields; see [`@sigilry/dapp`](../../packages/dapp/#generated-schemas).

Event methods are defined in the OpenRPC spec but delivered as provider events:

* `accountsChanged`
* `txChanged`
* `statusChanged` — CIP-103 §4.2.2 provider status transitions; disconnects route through here per §4.2.2:216
* `connected` — CIP-103 login-flow completion event (not one of the §4.2.2 three); identical payload to `statusChanged`

## Error handling

`@sigilry/dapp` exposes common error codes via `RpcErrorCode` and helpers like `rpcError`.

```ts
import "@sigilry/dapp/browser-globals";
import { RpcClientError } from "@sigilry/dapp";

async function getStatus() {
  if (!window.canton) throw new Error("No Canton wallet injected");
  try {
    return await window.canton.request({ method: "status" });
  } catch (err) {
    const parsed = RpcClientError.fromError(err);
    console.error(parsed.code, parsed.message);
    throw parsed;
  }
}

getStatus();
```

## Validation

`createCantonServer` validates params using Zod schemas generated from OpenRPC. Invalid params return `RpcErrorCode.INVALID_PARAMS` with a concise error message.
