SDK Reference: Solana Client

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.

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

ConstantTypeValue
SolanaClient.CAPABILITY_IDstring"solana@1.0.0"
SolanaClient.CAPABILITY_NAMEstring"solana"
SolanaClient.CAPABILITY_VERSIONstring"1.0.0"
SolanaClient.SUPPORTED_CHAIN_SELECTORS["solana-mainnet"]bigint124615329519749607n
SolanaClient.SUPPORTED_CHAIN_SELECTORS["solana-devnet"]bigint16423721717087811551n

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:

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

SolanaWriteCreReportRequestJson

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

FieldTypeRequiredDescription
receiverstringYesHex-encoded 32-byte program ID of the receiver program
remainingAccountsAccountMetaJson[]YesOrdered list of accounts required by the forwarder and receiver
reportReportYesThe signed report returned by runtime.report()
computeConfigComputeConfigJsonNoOptional compute budget configuration

AccountMetaJson

FieldTypeRequiredDescription
publicKeystringYesBase64-encoded 32-byte public key
isWritablebooleanNoWhether the account is writable (default: false)

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

ComputeConfigJson

FieldTypeRequiredDescription
computeUnitLimitstringNoMaximum compute units for the transaction (default: 290000)

WriteReportReply

FieldTypeDescription
txStatusSolanaTxStatusTX_STATUS_SUCCESS, TX_STATUS_ABORTED, or TX_STATUS_FATAL
txSignatureUint8ArrayTransaction signature bytes (optional)
errorMessagestringError message if the transaction failed (optional)

Usage example

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

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:

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

GetAccountInfoWithOptsRequestJson

FieldTypeRequiredDescription
accountstringYesBase64-encoded 32-byte account public key. Use bytesToBase64(solanaAddressToBytes(base58Address)) to build it from a base58 address.
optsGetAccountInfoOptsJsonNoEncoding, commitment, and slicing options.

GetAccountInfoOptsJson

FieldTypeDescription
encodingEncodingTypeJson"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".
commitmentCommitmentTypeJson"COMMITMENT_TYPE_FINALIZED", "COMMITMENT_TYPE_CONFIRMED", or "COMMITMENT_TYPE_PROCESSED".
dataSliceDataSliceJsonOptional {offset, length} window to fetch only part of the account data.
minContextSlotstringOptional 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.

FieldTypeDescription
valueAccountThe account, or undefined if it does not exist.

Account

FieldTypeDescription
lamportsbigintBalance in lamports.
ownerUint8Array32-byte program ID that owns the account.
dataDataBytesOrJSONAccount data, a oneof: data.body is {case: "raw", value: Uint8Array} or {case: "json", value: Uint8Array} depending on the requested encoding.
executablebooleantrue if this is a program account.
rentEpochbigintNext rent epoch.
spacebigintData length in bytes.

Usage: see the Onchain Read guide 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:

MethodDescription
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:

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:

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:

function solanaAddressToBytes(base58Address: string): Uint8Array

Usage:

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:

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:

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:

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:

function encodeForwarderReport(report: ForwarderReport): Uint8Array
interface ForwarderReport {
  accountHash: Uint8Array // must be exactly 32 bytes
  payload: Uint8Array // your Borsh-encoded struct
}

Usage:

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:

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:

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.

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:

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

Usage:

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

NetworkString NameNumeric ID
Solana Mainnetsolana-mainnet124615329519749607
Solana Devnetsolana-devnet16423721717087811551

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():

{
  "chainSelector": "124615329519749607"
}
const client = new SolanaClient(BigInt(config.chainSelector))

Get the latest Chainlink content straight to your inbox.