# Unified Indexer Service

The Unified Indexer Service (UIS) is the blockchain indexing architecture used by Ripple Custody for ledger-specific indexing, event processing, and ledger APIs. UIS uses a decomposed, chain-specific adapter architecture with isolated ledger and network components.

For a complete and up-to-date list of which ledgers are supported, please refer to the [Supported blockchain ledgers](/products/custody/v1.40/reference/supported-ledgers) page.

UIS is available for SaaS deployments and for on-premises deployments from v1.26. If you are migrating an on-premises deployment from legacy indexers to UIS, see the [UIS on-premises migration guide](/products/custody/v1.40/operations-and-maintenance/upgrading/unified-indexer-service-migration).

## How it works

The Unified Indexer Service indexes blockchain data and exposes it to Ripple Custody through a small set of services:

| Service | Description |
|  --- | --- |
| Indexer | Reads blocks from a blockchain node and records them. One indexer runs per ledger and network (for example, Solana devnet and Solana mainnet each run their own indexer), so an issue on one network does not affect the others. |
| Processor | Turns indexed blocks into the transaction events consumed by Ripple Custody. Shared across all ledgers. |
| Blockchain API | The single interface for blockchain operations — retrieves events, checks balances, prepares and broadcasts transactions. Shared across all ledgers. |
| Cockpit | Holds the ledger and network configuration the UIS runs against. This configuration is managed by Ripple Custody. |


For on-premises deployments, each indexer connects to a blockchain node that you provision — see [On-premises node requirements](#on-premises-node-requirements) below.

## Supported chains and indexer types

Ripple Custody supports a wide range of blockchains. Depending on the chain, indexing is handled either by UIS or by a standalone indexer. For on-premises deployments from v1.26:

- Solana, TRON, and XRPL use UIS automatically and do not require a per-network UIS configuration setting.
- Arbitrum, Base, and Optimism require UIS and must be explicitly configured with `type: "uis"` to be operable.
- Ethereum, Polygon, and Stellar continue to use existing standalone indexers unless you explicitly configure them to use UIS.


Pending change for on-premises deployments
On-premises customers should be aware that a rewrite of the UIS will be available for on-premises deployment starting in the next LTS release. At that time, those blockchains configured with `type: "uis"` will need to be updated to use the new UIS.

## On-premises node requirements

For an on-premises deployment of UIS, you are responsible for provisioning and maintaining your own blockchain nodes. The service must be able to connect to these nodes to index transactions. The following table lists minimum node requirements for on-premises UIS deployments. Check the configuration packaged with your release for release-specific changes.

| Blockchain | Node type | Minimum version | Connection | Archive requirement | Additional details |
|  --- | --- | --- | --- | --- | --- |
| **Arbitrum** | Geth compatible | v3.7.X | JSON-RPC over HTTP | Non-Archive | Debug mode must be enabled. |
| **Base** | Geth compatible | v0.14.1 | JSON-RPC over HTTP | Non-Archive | Debug mode must be enabled. |
| **Ethereum** | Geth | v1.16.4 | JSON-RPC over HTTP | Archive (Required) | Debug APIs must be enabled. High request volume (~1.2k - 300k/hour). |
| **Optimism** | Geth compatible | v1.101511 | JSON-RPC over HTTP | Non-Archive | Debug mode must be enabled. |
| **Polygon** | Geth compatible | v1.16.4 | JSON-RPC over HTTP | Archive (Required) | Debug mode must be enabled. |
| **Solana** | Agave | mainnet 2.3.10 / devnet 3.0.0 | JSON-RPC over HTTP | Archive Recommended | Estimated request volume is ~9000/hour. No debug mode needed. |
| **Stellar** | Horizon | v23.0.0 | HTTP | Archive (Preferred) | Requires `application/x-www-form-urlencoded` content-type for broadcasting transactions. |
| **TRON** | FullNode | v4.8.0 | RPC over HTTP | Archive (Preferred) | Estimated request volume is ~150k/day. |
| **XRPL** | FullNode | 2.6.X | HTTP | Archive Recommended | Request volume is not based on tracked accounts. |


## Configuration

### SaaS deployments

For SaaS deployments, UIS is enabled and managed by Ripple for supported chains.

### On-premises deployments

For on-premises deployments, UIS is available from v1.26 or later.

**Use UIS automatically:**

| Chain | Status |
|  --- | --- |
| Solana | Uses UIS automatically. No per-network `type: "uis"` setting is required. |
| XRPL | Uses UIS automatically. No per-network `type: "uis"` setting is required. |
| TRON | Uses UIS automatically. No per-network `type: "uis"` setting is required. |


**Must be explicitly configured to use UIS:**

| Chain | Status |
|  --- | --- |
| Arbitrum | Requires UIS. Configure the network with `type: "uis"` and provide node access settings. |
| Base | Requires UIS. Configure the network with `type: "uis"` and provide node access settings. |
| Optimism | Requires UIS. Configure the network with `type: "uis"` and provide node access settings. |
| Ethereum | Optional. You can continue using the legacy indexer or migrate to UIS. |
| Polygon | Optional. You can continue using the legacy indexer or migrate to UIS. |
| Stellar | Optional. You can continue using the legacy indexer or migrate to UIS. |


Arbitrum, Base, and Optimism require UIS because there is no supported legacy-indexer path for those chains. They still need explicit configuration in on-premises deployments because Ripple Custody must know which network to run, which node endpoint to use, and which authentication settings to apply.

Other EVM chains like Ethereum and Polygon can optionally use UIS or continue with legacy indexers.

Stellar can also optionally use UIS or continue with legacy indexers.

Migrating a chain to the Unified Indexer is a one-way process and cannot be rolled back.

Please plan your migration carefully. For any questions about the deployment process, please contact your CPE or our Support team.

### Configuration example

To enable UIS for a specific chain, set the `type` parameter to `"uis"` in that network's configuration block within your Helm chart's `values.yaml` file.

The example code below shows the correct structure for enabling the UIS for an Optimism Sepolia testnet:

```yaml
ledgers:
  evm:
    networks:
      - name: optimism-sepolia
        type: "uis"  # Enable UIS for this network
        raw_config: |
          tracker.opindexer-sepolia.base-url = "http://api-management-uis"
          ...
        indexer:
          ...
          node:
            # URL for your provisioned Optimism Sepolia node.
            url: "http://your-optimism-sepolia-node-url"
```

For complete step-by-step migration instructions, including pre-migration setup, database preparation, and validation steps, see the [UIS on-premises migration guide](/products/custody/v1.40/operations-and-maintenance/upgrading/unified-indexer-service-migration).

### Node authentication for EVM chains

If your EVM blockchain node requires authentication (for example, a Besu node that issues short-lived JWTs, or a third-party provider that expects a static header token), add an `authentication` block to the network's `indexer.node` config. This automatically deploys a Node Gateway sidecar in the same pod as the EVM indexer.

#### Header authentication (static token or API key)

Use `mode: header` to inject a fixed key-value pair into every outbound request:

```yaml
ledgers:
  evm:
    networks:
      - name: mainnet
        type: "uis"
        indexer:
          node:
            url: "https://eth-node-provider.internal/"
            authentication:
              mode: header
              header:
                key: "x-auth-token"
                value: "secret"
```

#### Custom JWT authentication

Use `mode: customJwt` when the node requires a short-lived bearer token fetched from a separate token endpoint. Node Gateway fetches and caches the token, refreshing it before expiry.

```yaml
ledgers:
  evm:
    networks:
      - name: testnet-goerli
        type: "uis"
        indexer:
          node:
            url: "https://example-mas-node.internal/"
            authentication:
              mode: customJwt
              customJwt:
                tokenUrl: "https://example.com/api/generate-access-token"
                tokenMethod: POST
                apiKeyHeader: "x-api-key"
                apiKeyValue: "your-api-key"
                requestBody:
                  signature: "your-signature"
                tokenJsonPath: data
                tokenExpirySeconds: 3600
                refreshBufferSeconds: 300
```

**`customJwt` field reference:**

| Field | Type | Required | Description |
|  --- | --- | --- | --- |
| `tokenUrl` | String (URL) | Yes | Endpoint that issues the access token. |
| `tokenMethod` | String | Yes | HTTP method for the token request (`POST` or `GET`). |
| `apiKeyHeader` | String | No | Header name to include in the token request for API-key authentication of the token endpoint itself. |
| `apiKeyValue` | String | No | Value for the `apiKeyHeader`. Store this in a Kubernetes Secret and inject via env var. |
| `requestBody` | Map | No | Key-value pairs sent as the JSON body of the token request. |
| `tokenJsonPath` | String | Yes | JSON path expression to extract the token value from the token endpoint response (e.g., `data` or `access_token`). |
| `tokenExpirySeconds` | Integer | Yes | Lifetime of the fetched token in seconds. Node Gateway caches the token for this duration. |
| `refreshBufferSeconds` | Integer | Yes | Seconds before expiry at which Node Gateway proactively fetches a new token. Must be less than `tokenExpirySeconds`. |