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
| 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:
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.
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 stringisWritable: Whether the account is writable. Defaults tofalse.
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 ofencodeForwarderReport()reportEncoder: Optional. Defaults toSOLANA_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
| 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():
{
"chainSelector": "124615329519749607"
}
const client = new SolanaClient(BigInt(config.chainSelector))
Related resources
- Solana Write Capability: Architecture reference and account layout
- Generating Solana Bindings: How to generate typed binding classes from your Anchor IDL
- Writing to Solana guide: Step-by-step tutorial
- Supported Networks: Chain selector values for all supported networks