SDK Reference: Solana Client

This page provides a reference for SolanaClient, the TypeScript SDK interface for writing data to Solana programs via the Keystone Forwarder. 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()

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.