# SDK Reference: Solana Client
Source: https://docs.chain.link/cre/reference/sdk/solana-client-ts
Last Updated: 2026-10-19

> For the complete documentation index, see [llms.txt](/llms.txt).

This page provides a reference for `SolanaClient`, the TypeScript SDK interface for reading from and writing to Solana programs. It covers the client class, all exported helper functions, and the chain selector reference for Solana networks.

## Client instantiation

Instantiate `SolanaClient` with the `bigint` chain selector for the Solana network you are targeting.

```typescript
import { SolanaClient } from "@chainlink/cre-sdk"

// Solana Mainnet
const client = new SolanaClient(124615329519749607n)

// Or use the supported chain selectors constant
const client = new SolanaClient(SolanaClient.SUPPORTED_CHAIN_SELECTORS["solana-mainnet"])
```

### Static constants

| Constant                                                   | Type     | Value                   |
| ---------------------------------------------------------- | -------- | ----------------------- |
| `SolanaClient.CAPABILITY_ID`                               | `string` | `"solana@1.0.0"`        |
| `SolanaClient.CAPABILITY_NAME`                             | `string` | `"solana"`              |
| `SolanaClient.CAPABILITY_VERSION`                          | `string` | `"1.0.0"`               |
| `SolanaClient.SUPPORTED_CHAIN_SELECTORS["solana-mainnet"]` | `bigint` | `124615329519749607n`   |
| `SolanaClient.SUPPORTED_CHAIN_SELECTORS["solana-devnet"]`  | `bigint` | `16423721717087811551n` |

***

## Write methods

### `writeReport()`

Submits a cryptographically signed report to a Solana program via the Keystone Forwarder. This is the primary method for writing data onchain from a CRE workflow. In practice, you call this indirectly through generated binding methods (`writeReportFrom<StructName>()`), which handle Borsh encoding and account hashing for you.

**Signature:**

```typescript
writeReport(
  runtime: Runtime<unknown>,
  input: SolanaWriteCreReportRequest | SolanaWriteCreReportRequestJson
): { result: () => WriteReportReply }
```

#### `SolanaWriteCreReportRequestJson`

The plain-object form accepted by `writeReport`. Generated binding methods build this internally.

| Field               | Type                | Required | Description                                                     |
| ------------------- | ------------------- | -------- | --------------------------------------------------------------- |
| `receiver`          | `string`            | Yes      | Hex-encoded 32-byte program ID of the receiver program          |
| `remainingAccounts` | `AccountMetaJson[]` | Yes      | Ordered list of accounts required by the forwarder and receiver |
| `report`            | `Report`            | Yes      | The signed report returned by `runtime.report()`                |
| `computeConfig`     | `ComputeConfigJson` | No       | Optional compute budget configuration                           |

#### `AccountMetaJson`

| Field        | Type      | Required | Description                                        |
| ------------ | --------- | -------- | -------------------------------------------------- |
| `publicKey`  | `string`  | Yes      | Base64-encoded 32-byte public key                  |
| `isWritable` | `boolean` | No       | Whether the account is writable (default: `false`) |

Use `solanaAccountMetasToJson()` to convert `SolanaAccountMeta[]` to this format.

#### `ComputeConfigJson`

| Field              | Type     | Required | Description                                                   |
| ------------------ | -------- | -------- | ------------------------------------------------------------- |
| `computeUnitLimit` | `string` | No       | Maximum compute units for the transaction (default: `290000`) |

#### `WriteReportReply`

| Field          | Type             | Description                                                    |
| -------------- | ---------------- | -------------------------------------------------------------- |
| `txStatus`     | `SolanaTxStatus` | `TX_STATUS_SUCCESS`, `TX_STATUS_ABORTED`, or `TX_STATUS_FATAL` |
| `txSignature`  | `Uint8Array`     | Transaction signature bytes (optional)                         |
| `errorMessage` | `string`         | Error message if the transaction failed (optional)             |

#### Usage example

The low-level call, shown for reference. In most workflows, use a generated binding instead.

```typescript
import {
  SolanaClient,
  solanaAccountMeta,
  solanaAccountMetasToJson,
  calculateAccountsHash,
  encodeForwarderReport,
  prepareSolanaReportRequest,
  bytesToHex,
  solanaAddressToBytes,
  type Runtime,
} from "@chainlink/cre-sdk"

const client = new SolanaClient(124615329519749607n)

const forwarderStateBytes = solanaAddressToBytes("ForwarderStateBase58...")
const forwarderAuthBytes = solanaAddressToBytes("ForwarderAuthBase58...")
const reportStateBytes = solanaAddressToBytes("ReportStateBase58...")

const remainingAccounts = [
  solanaAccountMeta(forwarderStateBytes, false),
  solanaAccountMeta(forwarderAuthBytes, false),
  solanaAccountMeta(reportStateBytes, true),
]

// 1. Borsh-encode your payload (generated bindings do this automatically)
const payload: Uint8Array = borshEncode({ price: 500000n, timestamp: BigInt(Date.now()) })

// 2. Generate a signed report
const report = runtime
  .report(
    prepareSolanaReportRequest(
      encodeForwarderReport({
        accountHash: calculateAccountsHash(remainingAccounts),
        payload,
      })
    )
  )
  .result()

// 3. Submit the report
const result = client
  .writeReport(runtime, {
    receiver: bytesToHex(solanaAddressToBytes("ReceiverProgramBase58...")),
    remainingAccounts: solanaAccountMetasToJson(remainingAccounts),
    report,
    computeConfig: { computeUnitLimit: "290000" },
  })
  .result()
```

***

## Read methods

`SolanaClient` exposes read methods for fetching consensus-verified data from Solana accounts and programs, served by a `ContractReader` on the Solana capability DON. There is no generated per-account "fetch" helper — you call these directly, then decode the result with the generated `decode<AccountName>Account()` function for your account type.

### `SolanaClient.getAccountInfoWithOpts()`

Fetches a single account's info, including its raw data.

**Signature:**

```typescript
getAccountInfoWithOpts(
  runtime: Runtime<unknown>,
  input: GetAccountInfoWithOptsRequest | GetAccountInfoWithOptsRequestJson
): { result: () => GetAccountInfoWithOptsReply }
```

#### `GetAccountInfoWithOptsRequestJson`

| Field     | Type                     | Required | Description                                                                                                                            |
| --------- | ------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `account` | `string`                 | Yes      | Base64-encoded 32-byte account public key. Use `bytesToBase64(solanaAddressToBytes(base58Address))` to build it from a base58 address. |
| `opts`    | `GetAccountInfoOptsJson` | No       | Encoding, commitment, and slicing options.                                                                                             |

#### `GetAccountInfoOptsJson`

| Field            | Type                 | Description                                                                                                                                                                             |
| ---------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `encoding`       | `EncodingTypeJson`   | `"ENCODING_TYPE_BASE58"` (accounts under 129 bytes only), `"ENCODING_TYPE_BASE64"` (any size), `"ENCODING_TYPE_BASE64_ZSTD"`, `"ENCODING_TYPE_JSON_PARSED"`, or `"ENCODING_TYPE_JSON"`. |
| `commitment`     | `CommitmentTypeJson` | `"COMMITMENT_TYPE_FINALIZED"`, `"COMMITMENT_TYPE_CONFIRMED"`, or `"COMMITMENT_TYPE_PROCESSED"`.                                                                                         |
| `dataSlice`      | `DataSliceJson`      | Optional `{offset, length}` window to fetch only part of the account data.                                                                                                              |
| `minContextSlot` | `string`             | Optional lower-bound slot for the read.                                                                                                                                                 |

#### `GetAccountInfoWithOptsReply`

The value returned by `.result()`. Unlike the request, this comes back with real typed fields (not the `...Json`
form) — byte fields are `Uint8Array`, not base64 strings.

| Field   | Type      | Description                                       |
| ------- | --------- | ------------------------------------------------- |
| `value` | `Account` | The account, or `undefined` if it does not exist. |

#### `Account`

| Field        | Type              | Description                                                                                                                                          |
| ------------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lamports`   | `bigint`          | Balance in lamports.                                                                                                                                 |
| `owner`      | `Uint8Array`      | 32-byte program ID that owns the account.                                                                                                            |
| `data`       | `DataBytesOrJSON` | Account data, a oneof: `data.body` is `{case: "raw", value: Uint8Array}` or `{case: "json", value: Uint8Array}` depending on the requested encoding. |
| `executable` | `boolean`         | `true` if this is a program account.                                                                                                                 |
| `rentEpoch`  | `bigint`          | Next rent epoch.                                                                                                                                     |
| `space`      | `bigint`          | Data length in bytes.                                                                                                                                |

**Usage:** see the [Onchain Read guide](/cre/guides/workflow/using-solana-client/onchain-read-ts) for a full,
step-by-step example, including decoding the returned bytes with a generated `decode<AccountName>Account()`.

### Other read methods

`SolanaClient` also exposes these lower-level read methods, following the same `(runtime, input): { result: () => XReply }` shape:

| Method                          | Description                                                 |
| ------------------------------- | ----------------------------------------------------------- |
| `getBalance()`                  | Lamport balance of an account.                              |
| `getBlock()`                    | A block's contents at a given slot.                         |
| `getMultipleAccountsWithOpts()` | `getAccountInfoWithOpts()`, batched for multiple accounts.  |
| `getProgramAccounts()`          | All accounts owned by a program, with optional filters.     |
| `getSignatureStatuses()`        | Confirmation status for one or more transaction signatures. |
| `getSlotHeight()`               | The current slot height.                                    |
| `getTransaction()`              | A confirmed transaction's details, given its signature.     |
| `getFeeForMessage()`            | The fee a compiled message would cost.                      |

***

## Helper functions

These functions are exported from `@chainlink/cre-sdk` and used when building Solana write requests, either directly or through generated bindings.

### `solanaAccountMeta()`

Builds an account entry for the `remainingAccounts` list.

**Signature:**

```typescript
function solanaAccountMeta(publicKey: Uint8Array | string, isWritable?: boolean): SolanaAccountMeta
```

**Parameters:**

- `publicKey`: The 32-byte public key as raw bytes or a base58-encoded string
- `isWritable`: Whether the account is writable. Defaults to `false`.

**Usage:**

```typescript
import { solanaAccountMeta } from "@chainlink/cre-sdk"

// From a base58 string
const account = solanaAccountMeta("ECL8142j2YQAvs9R9geSsRnkVH2wLEi7soJCRyJ74cfL", true)

// From raw bytes
const account = solanaAccountMeta(rawBytes, false)
```

***

### `solanaAddressToBytes()`

Converts a base58-encoded Solana address to its raw 32-byte representation.

**Signature:**

```typescript
function solanaAddressToBytes(base58Address: string): Uint8Array
```

**Usage:**

```typescript
import { solanaAddressToBytes } from "@chainlink/cre-sdk"

const bytes = solanaAddressToBytes("ECL8142j2YQAvs9R9geSsRnkVH2wLEi7soJCRyJ74cfL")
// → Uint8Array(32)
```

***

### `solanaAccountMetasToJson()`

Converts `SolanaAccountMeta[]` to the `AccountMetaJson[]` shape expected by `SolanaClient.writeReport()`. Generated bindings call this internally.

**Signature:**

```typescript
function solanaAccountMetasToJson(accounts: ReadonlyArray<SolanaAccountMeta>): AccountMetaJson[]
```

***

### `calculateAccountsHash()`

Computes the SHA-256 hash of the concatenated public keys of the given accounts. This hash is embedded in the report payload and verified on-chain by the Keystone Forwarder.

**Signature:**

```typescript
function calculateAccountsHash(accounts: ReadonlyArray<SolanaAccountInput | null | undefined>): Uint8Array
```

The hash is computed over the raw 32-byte public keys in the order provided. Account order matters: swapping two accounts produces a different hash.

**Usage:**

```typescript
import { calculateAccountsHash, solanaAccountMeta } from "@chainlink/cre-sdk"

const accounts = [
  solanaAccountMeta(forwarderState, false),
  solanaAccountMeta(forwarderAuthority, false),
  solanaAccountMeta(reportState, true),
]

const accountHash = calculateAccountsHash(accounts)
// → Uint8Array(32) [SHA-256 of concatenated public keys]
```

***

### `encodeForwarderReport()`

Borsh-encodes a `ForwarderReport` struct for the Keystone Forwarder program. The encoding format is `[32-byte accountHash][u32-LE payload length][payload bytes]`.

**Signature:**

```typescript
function encodeForwarderReport(report: ForwarderReport): Uint8Array
```

```typescript
interface ForwarderReport {
  accountHash: Uint8Array // must be exactly 32 bytes
  payload: Uint8Array // your Borsh-encoded struct
}
```

**Usage:**

```typescript
import { encodeForwarderReport, calculateAccountsHash, solanaAccountMeta } from "@chainlink/cre-sdk"

const encoded = encodeForwarderReport({
  accountHash: calculateAccountsHash(remainingAccounts),
  payload: borshEncodedPayload,
})
```

***

### `prepareSolanaReportRequest()`

Prepares a `ReportRequestJson` for `runtime.report()` using the Solana default encoder (`solana` / `ecdsa` / `keccak256`). Pass the result directly to `runtime.report()`.

**Signature:**

```typescript
function prepareSolanaReportRequest(payload: Uint8Array, reportEncoder?: ReportEncoder): ReportRequestJson
```

**Parameters:**

- `payload`: The encoded payload bytes — typically the output of `encodeForwarderReport()`
- `reportEncoder`: Optional. Defaults to `SOLANA_DEFAULT_REPORT_ENCODER`

**Usage:**

```typescript
import { prepareSolanaReportRequest, encodeForwarderReport } from "@chainlink/cre-sdk"

const reportRequest = prepareSolanaReportRequest(encodeForwarderReport({ accountHash, payload }))

const report = runtime.report(reportRequest).result()
```

***

### `SOLANA_DEFAULT_REPORT_ENCODER`

The default encoder configuration for Solana write operations.

```typescript
const SOLANA_DEFAULT_REPORT_ENCODER = {
  encoderName: "solana",
  signingAlgo: "ecdsa",
  hashingAlgo: "keccak256",
}
```

Pass to `prepareSolanaReportRequest()` to override encoding parameters.

***

### `encodeBorshVecU32()`

Encodes a `Vec<Bytes>` in Borsh format: `[u32-LE element count][concatenated element payloads]`. Use this when your receiver program's `on_report` accepts a `Vec<T>` of items.

**Signature:**

```typescript
function encodeBorshVecU32(elementPayloads: ReadonlyArray<Uint8Array>): Uint8Array
```

**Usage:**

```typescript
import { encodeBorshVecU32 } from "@chainlink/cre-sdk"

const vec = encodeBorshVecU32([item1Bytes, item2Bytes, item3Bytes])
```

Generated binding methods ending in `s` (e.g., `writeReportFromPriceDatas()`) use this internally to encode arrays.

***

## Chain selectors

| Network        | String Name    | Numeric ID           |
| -------------- | -------------- | -------------------- |
| Solana Mainnet | solana-mainnet | 124615329519749607   |
| Solana Devnet  | solana-devnet  | 16423721717087811551 |

In your workflow config (e.g., `config.staging.json`), store the numeric ID as a **string** to avoid JSON precision loss, then convert with `BigInt()`:

```json
{
  "chainSelector": "124615329519749607"
}
```

```typescript
const client = new SolanaClient(BigInt(config.chainSelector))
```

## Related resources

- **[Solana Read & Write Capabilities](/cre/capabilities/solana-read-write)**: Architecture reference and account layout
- **[Generating Solana Bindings](/cre/guides/workflow/using-solana-client/generating-bindings-ts)**: How to generate typed binding classes from your Anchor IDL
- **[Reading from Solana guide](/cre/guides/workflow/using-solana-client/onchain-read-ts)**: Step-by-step tutorial
- **[Writing to Solana guide](/cre/guides/workflow/using-solana-client/onchain-write-ts)**: Step-by-step tutorial
- **[Solana Log Trigger reference](/cre/reference/sdk/triggers/solana-log-trigger-ts)**: Filter configuration and payload fields
- **[Supported Networks](/cre/supported-networks-ts)**: Chain selector values for all supported networks