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

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

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

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

## Client instantiation

```go
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

| Constant               | Value                  |
| ---------------------- | ---------------------- |
| `solana.SolanaMainnet` | `124615329519749607`   |
| `solana.SolanaDevnet`  | `16423721717087811551` |

### `ChainSelectorFromName()`

```go
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:**

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

#### `WriteCreReportRequest`

| Field               | Type             | Description                                             |
| ------------------- | ---------------- | ------------------------------------------------------- |
| `RemainingAccounts` | `[]*AccountMeta` | Ordered accounts required by the forwarder and receiver |
| `Receiver`          | `[]byte`         | 32-byte raw program ID of the receiver program          |
| `ComputeConfig`     | `*ComputeConfig` | Optional compute budget configuration                   |
| `Report`            | `*cre.Report`    | The signed report returned by `runtime.Report()`        |

#### `AccountMeta`

| Field        | Type     | Description                     |
| ------------ | -------- | ------------------------------- |
| `PublicKey`  | `[]byte` | 32-byte raw public key          |
| `IsWritable` | `bool`   | Whether the account is writable |

#### `ComputeConfig`

| Field              | Type     | Description                                                   |
| ------------------ | -------- | ------------------------------------------------------------- |
| `ComputeUnitLimit` | `uint32` | Maximum compute units for the transaction (default: `290000`) |

#### `WriteReportReply`

| Field          | Type       | Description                                                             |
| -------------- | ---------- | ----------------------------------------------------------------------- |
| `TxStatus`     | `TxStatus` | `TX_STATUS_SUCCESS`, `TX_STATUS_ABORTED`, or `TX_STATUS_FATAL`          |
| `TxSignature`  | `[]byte`   | Transaction signature bytes, accessed via `GetTxSignature()` (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.

```go
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:**

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

#### `GetAccountInfoWithOptsRequest`

| Field     | Type                  | Description                                |
| --------- | --------------------- | ------------------------------------------ |
| `Account` | `[]byte`              | 32-byte account public key.                |
| `Opts`    | `*GetAccountInfoOpts` | Encoding, commitment, and slicing options. |

#### `GetAccountInfoOpts`

| Field            | Type                    | Description                                                                                                                                                                   |
| ---------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Encoding`       | `solana.EncodingType`   | `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`     | `solana.CommitmentType` | `COMMITMENT_TYPE_FINALIZED`, `COMMITMENT_TYPE_CONFIRMED`, or `COMMITMENT_TYPE_PROCESSED`.                                                                                     |
| `DataSlice`      | `*solana.DataSlice`     | Optional `{Offset, Length}` window to fetch only part of the account data.                                                                                                    |
| `MinContextSlot` | `uint64`                | Optional lower-bound slot for the read.                                                                                                                                       |

#### `GetAccountInfoWithOptsReply`

| Field   | Type              | Description                                 |
| ------- | ----------------- | ------------------------------------------- |
| `Value` | `*solana.Account` | The account, or `nil` if it does not exist. |

#### `Account`

| Field        | Type                      | Description                                                                                                                                                        |
| ------------ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Lamports`   | `uint64`                  | Balance in lamports.                                                                                                                                               |
| `Owner`      | `[]byte`                  | 32-byte program ID that owns the account.                                                                                                                          |
| `Data`       | `*solana.DataBytesOrJSON` | Account data. Use `GetRaw()` for the encoded bytes (matches your requested `Encoding`) or `GetJson()` when using `ENCODING_TYPE_JSON_PARSED`/`ENCODING_TYPE_JSON`. |
| `Executable` | `bool`                    | `true` if this is a program account.                                                                                                                               |
| `RentEpoch`  | `*pb.BigInt`              | Next rent epoch.                                                                                                                                                   |
| `Space`      | `uint64`                  | Data length in bytes.                                                                                                                                              |

**Usage:** see the [Onchain Read guide](/cre/guides/workflow/using-solana-client/onchain-read-go) 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:

| 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.                      |

***

## `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.

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

#### `ForwarderReport.Marshal()`

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

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

**Usage:**

```go
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.

```go
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:**

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

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

***

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

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

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

## 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-go)**: How to generate typed Go structs from your Anchor IDL
- **[Reading from Solana guide](/cre/guides/workflow/using-solana-client/onchain-read-go)**: Step-by-step tutorial
- **[Writing to Solana guide](/cre/guides/workflow/using-solana-client/onchain-write-go)**: Step-by-step tutorial
- **[Solana Log Trigger reference](/cre/reference/sdk/triggers/solana-log-trigger-go)**: Filter configuration and payload fields
- **[Supported Networks](/cre/supported-networks-go)**: Chain selector values for all supported networks