SDK Reference: Solana Client

This page provides a reference for solana.Client, the Go SDK interface for reading from and writing to Solana programs. It covers the client type, the bindings package helpers, and the chain selector reference for Solana networks.

Import paths

import (
    solana "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/solana"
    "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/solana/bindings"
)

Client instantiation

import solana "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/solana"

// Solana Mainnet using the package constant
client := &solana.Client{ChainSelector: solana.SolanaMainnet}

// Solana Devnet
client := &solana.Client{ChainSelector: solana.SolanaDevnet}

// Or use ChainSelectorFromName
selector, err := solana.ChainSelectorFromName("solana-mainnet")
client := &solana.Client{ChainSelector: selector}

Chain selector constants

ConstantValue
solana.SolanaMainnet124615329519749607
solana.SolanaDevnet16423721717087811551

ChainSelectorFromName()

func ChainSelectorFromName(name string) (uint64, error)

Accepts "solana-mainnet" or "solana-devnet". Returns an error for unknown names.


Write methods

Client.WriteReport()

Submits a cryptographically signed report to a Solana program via the Keystone Forwarder. In most workflows, you call generated binding methods (WriteReportFrom<StructName>()) rather than this method directly.

Signature:

func (c *Client) WriteReport(runtime cre.Runtime, input *WriteCreReportRequest) cre.Promise[*WriteReportReply]

WriteCreReportRequest

FieldTypeDescription
RemainingAccounts[]*AccountMetaOrdered accounts required by the forwarder and receiver
Receiver[]byte32-byte raw program ID of the receiver program
ComputeConfig*ComputeConfigOptional compute budget configuration
Report*cre.ReportThe signed report returned by runtime.Report()

AccountMeta

FieldTypeDescription
PublicKey[]byte32-byte raw public key
IsWritableboolWhether the account is writable

ComputeConfig

FieldTypeDescription
ComputeUnitLimituint32Maximum compute units for the transaction (default: 290000)

WriteReportReply

FieldTypeDescription
TxStatusTxStatusTX_STATUS_SUCCESS, TX_STATUS_ABORTED, or TX_STATUS_FATAL
TxSignature[]byteTransaction signature bytes, accessed via GetTxSignature() (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 (
    "encoding/base58"
    "time"

    "github.com/smartcontractkit/cre-sdk-go/cre"
    solana "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/solana"
    "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/solana/bindings"
    binary "github.com/gagliardetto/binary"
)

client := &solana.Client{ChainSelector: solana.SolanaMainnet}

forwarderStateBytes, _ := base58.Decode("ForwarderStateBase58...")
forwarderAuthBytes, _ := base58.Decode("ForwarderAuthBase58...")
reportStateBytes, _ := base58.Decode("ReportStateBase58...")
receiverBytes, _ := base58.Decode("ReceiverProgramBase58...")

accounts := []*solana.AccountMeta{
    {PublicKey: forwarderStateBytes, IsWritable: false},
    {PublicKey: forwarderAuthBytes, IsWritable: false},
    {PublicKey: reportStateBytes, IsWritable: true},
}

// 1. Borsh-encode your payload (generated bindings do this automatically)
type PriceData struct {
    Price     uint64
    Timestamp int64
}
var buf bytes.Buffer
enc := binary.NewBorshEncoder(&buf)
enc.Encode(PriceData{Price: 500000, Timestamp: time.Now().Unix()})
payload := buf.Bytes()

// 2. Compute the account hash and build the forwarder report
accountHash := bindings.CalculateAccountsHash(accounts)
forwarderReport := bindings.ForwarderReport{AccountHash: accountHash, Payload: payload}
encoded, err := forwarderReport.Marshal()

// 3. Generate a signed report
report := runtime.Report(cre.ReportRequest{
    EncodedPayload: base64.StdEncoding.EncodeToString(encoded),
    EncoderName:    "solana",
    SigningAlgo:    "ecdsa",
    HashingAlgo:    "keccak256",
}).Result()

// 4. Submit the report
result := client.WriteReport(runtime, &solana.WriteCreReportRequest{
    RemainingAccounts: accounts,
    Receiver:          receiverBytes,
    Report:            report,
}).Result()

Read methods

solana.Client 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 Codec.Decode<AccountName>() for your account type.

Client.GetAccountInfoWithOpts()

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

Signature:

func (c *Client) GetAccountInfoWithOpts(runtime cre.Runtime, input *GetAccountInfoWithOptsRequest) cre.Promise[*GetAccountInfoWithOptsReply]

GetAccountInfoWithOptsRequest

FieldTypeDescription
Account[]byte32-byte account public key.
Opts*GetAccountInfoOptsEncoding, commitment, and slicing options.

GetAccountInfoOpts

FieldTypeDescription
Encodingsolana.EncodingTypeENCODING_TYPE_BASE58 (accounts under 129 bytes only), ENCODING_TYPE_BASE64 (any size), ENCODING_TYPE_BASE64_ZSTD, ENCODING_TYPE_JSON_PARSED, or ENCODING_TYPE_JSON.
Commitmentsolana.CommitmentTypeCOMMITMENT_TYPE_FINALIZED, COMMITMENT_TYPE_CONFIRMED, or COMMITMENT_TYPE_PROCESSED.
DataSlice*solana.DataSliceOptional {Offset, Length} window to fetch only part of the account data.
MinContextSlotuint64Optional lower-bound slot for the read.

GetAccountInfoWithOptsReply

FieldTypeDescription
Value*solana.AccountThe account, or nil if it does not exist.

Account

FieldTypeDescription
Lamportsuint64Balance in lamports.
Owner[]byte32-byte program ID that owns the account.
Data*solana.DataBytesOrJSONAccount data. Use GetRaw() for the encoded bytes (matches your requested Encoding) or GetJson() when using ENCODING_TYPE_JSON_PARSED/ENCODING_TYPE_JSON.
Executablebooltrue if this is a program account.
RentEpoch*pb.BigIntNext rent epoch.
Spaceuint64Data length in bytes.

Usage: see the Onchain Read guide for a full, step-by-step example, including decoding the returned bytes with a generated Codec.Decode<AccountName>().

Other read methods

solana.Client also exposes these lower-level read methods, following the same runtime, *XRequest) cre.Promise[*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.

bindings package

The bindings package (github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/solana/bindings) provides the serialization primitives used by generated binding code. You can also use them directly when writing low-level Solana write logic.

ForwarderReport

Represents the Borsh-serialized report format expected by the Keystone Forwarder program.

type ForwarderReport struct {
    AccountHash [32]byte
    Payload     []byte
}

ForwarderReport.Marshal()

Serializes the report into Borsh bytes: [32-byte accountHash][u32-LE payload length][payload].

func (obj ForwarderReport) Marshal() ([]byte, error)

Usage:

report := bindings.ForwarderReport{
    AccountHash: bindings.CalculateAccountsHash(accounts),
    Payload:     borshEncodedPayload,
}

encoded, err := report.Marshal()

CalculateAccountsHash()

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

func CalculateAccountsHash(accs []*solana.AccountMeta) [32]byte

nil entries in the slice are skipped. Account order matters: swapping two accounts produces a different hash.

Usage:

accounts := []*solana.AccountMeta{
    {PublicKey: forwarderStateBytes},
    {PublicKey: forwarderAuthBytes},
    {PublicKey: reportStateBytes},
}

hash := bindings.CalculateAccountsHash(accounts)
// → [32]byte

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 precision loss, and use the json:",string" struct tag:

{
  "chainSelector": "124615329519749607"
}
type Config struct {
    ChainSelector uint64 `json:"chainSelector,string"`
}

Get the latest Chainlink content straight to your inbox.