# Generating Solana Bindings
Source: https://docs.chain.link/cre/guides/workflow/using-solana-client/generating-bindings-go
Last Updated: 2026-07-08

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

To interact with a Solana program from your Go workflow, you generate **bindings** from the program's [Anchor IDL](https://www.anchor-lang.com/docs/references/idl). Bindings are typed Go structs and methods that handle Borsh encoding, account hashing, and report submission automatically.

The Solana CRE capability is write-only. For each Anchor struct in your IDL, the generator creates a `WriteReportFrom<StructName>()` method. Your workflow calls this method with the struct data and the required accounts; the generated code handles everything else.

> **NOTE: CLI version requirement**
>
> Solana binding generation and Solana write simulation require **CRE CLI v1.24.0 or later**. Run `cre version` to
> check, then `cre update` if needed.

> **NOTE: TypeScript support**
>
> `cre generate-bindings solana` also supports TypeScript. See [Generating Solana Bindings
> (TypeScript)](/cre/guides/workflow/using-solana-client/generating-bindings-ts) for details.

## The generation process

The CRE CLI provides an automated binding generator that reads Anchor IDLs and creates corresponding Go packages.

The target language is **auto-detected** from your project files (presence of `go.mod` picks Go). You can also force Go explicitly with the `--language` flag:

```bash
cre generate-bindings solana --language go
```

Your project must already be a Go module (`go.mod` at the project root, as created by `cre init`). Without `go.mod`, the generator writes files but then fails when resolving Go dependencies.

### Step 1: Add your Anchor IDL

Place your program's Anchor IDL file in `contracts/solana/src/idl/`. The IDL is a JSON file that Anchor generates when you build your program:

```bash
# In your Anchor project
anchor build
# IDL is written to: target/idl/<program-name>.json
```

Copy it into your CRE project:

```bash
mkdir -p contracts/solana/src/idl
cp /path/to/your-anchor-project/target/idl/my_program.json contracts/solana/src/idl/
```

### Step 2: Generate the bindings

From your **project root**, run:

```bash
cre generate-bindings solana
```

This reads all `.json` IDL files in `contracts/solana/src/idl/` and generates Go packages in `contracts/solana/src/generated/`. For each IDL, the generator creates a package directory (for example `data_storage/`) with the binding sources, including:

- Struct types and `WriteReportFrom<StructName>()` methods
- A mock for testing without a live network

After generation, run `go mod tidy` if you need to sync new dependencies.

## Using generated bindings

### For onchain writes

For each struct in your IDL's `types` section, the generator creates a `WriteReportFrom<StructName>()` method that Borsh-encodes your data, builds the forwarder report, and submits it in one step. These methods return a `Promise`, which you must `.Await()` to get the result after consensus.

**Example: A minimal `DataStorage` IDL**

The following IDL is enough to generate a `WriteReportFromUserData()` helper. Save it as `contracts/solana/src/idl/data_storage.json`.

```json
{
  "address": "64Q1Xu7AEbc2xgaN21zZU1y1mkaLJNnP5cHFkthGuW31",
  "metadata": {
    "name": "data_storage",
    "version": "0.1.0",
    "spec": "0.1.0",
    "description": "Minimal CRE Solana write example IDL"
  },
  "instructions": [
    {
      "name": "on_report",
      "discriminator": [214, 173, 18, 221, 173, 148, 151, 208],
      "accounts": [],
      "args": [
        { "name": "_metadata", "type": "bytes" },
        { "name": "payload", "type": "bytes" }
      ]
    }
  ],
  "accounts": [],
  "events": [],
  "errors": [],
  "types": [
    {
      "name": "UserData",
      "type": {
        "kind": "struct",
        "fields": [
          { "name": "key", "type": "string" },
          { "name": "value", "type": "string" }
        ]
      }
    }
  ]
}
```

After running `cre generate-bindings solana`, use the generated `data_storage` package in your workflow:

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

	"<project-name>/contracts/solana/src/generated/data_storage"
)

// In your workflow handler...
client := &solana.Client{ChainSelector: config.ChainSelector}
ds, err := data_storage.NewDataStorage(client)
if err != nil {
	return "", err
}

// remainingAccounts: Index 0 forwarderState, 1 forwarderAuthority, 2+ receiver accounts
accounts := []*solana.AccountMeta{
	{PublicKey: forwarderStatePk[:], IsWritable: false},
	{PublicKey: forwarderAuthPk[:], IsWritable: false},
	{PublicKey: reportStatePk[:], IsWritable: true},
}

// Pass the struct data directly — types are derived from the IDL
result, err := ds.WriteReportFromUserData(runtime, data_storage.UserData{
	Key:   "price",
	Value: "500000",
}, accounts, &solana.ComputeConfig{ComputeLimit: 200_000}).Await()
```

For a full walkthrough including config, simulation, and production deployment, see [Writing to Solana](/cre/guides/workflow/using-solana-client/onchain-write-go).

> **NOTE: What does the WriteReport helper do?**
>
> The `WriteReportFromUserData` method Borsh-encodes the `UserData` struct, hashes `remainingAccounts` via
> `CalculateAccountsHash`, encodes a forwarder report and calls `runtime.GenerateReport()` with the `solana` encoder,
> calls the Solana client's `WriteReport` method to submit it, and returns a `Promise` that resolves with the
> transaction details once confirmed.

## What the CLI generates

The generator creates a Go package for each IDL file in `contracts/solana/src/generated/<program_name>/`.

What's inside depends on your IDL:

- **For all programs**:
  - A `<ProgramName>` struct and `New<ProgramName>(client)` constructor (program ID from the IDL).
  - Codec helpers for encoding structs.
- **For onchain writes** (each struct in `types`):
  - A `WriteReportFrom<StructName>(runtime, input, remainingAccounts, computeConfig)` method that returns a `cre.Promise[*solana.WriteReportReply]` you `.Await()`.
  - A `WriteReportFrom<StructName>s(...)` variant for Borsh `Vec` payloads.

## `accounts` layout

Every Solana write requires an `[]*solana.AccountMeta` slice. The Keystone Forwarder (and the Devnet mock forwarder used in simulation) expects:

| Index | Account              | `IsWritable`            | How to obtain                                                                                      |
| ----- | -------------------- | ----------------------- | -------------------------------------------------------------------------------------------------- |
| 0     | `forwarderState`     | `false`                 | Provided by Chainlink for the forwarder deployment (mock values are built into the CLI for Devnet) |
| 1     | `forwarderAuthority` | `false`                 | PDA derived from `["forwarder", forwarderState, receiverProgram]` under the forwarder program ID   |
| 2+    | Receiver accounts    | Depends on your program | Defined by your Anchor program's `on_report` instruction                                           |

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

> **TIP: forwarderAuthority derivation**
>
> Use `github.com/gagliardetto/solana-go`'s `FindProgramAddress` to derive the `forwarderAuthority` PDA and store it in
> config. The seeds are: `[][]byte{[]byte("forwarder"), forwarderStateBytes, receiverProgramBytes}` under the forwarder
> program ID.

## Best practices

1. **Regenerate when needed**: Re-run `cre generate-bindings solana` whenever your Anchor IDL changes. Do not edit generated files by hand.
2. **Always pass `ComputeConfig`**: Solana simulation rejects a nil or zero `ComputeLimit`. Pass `&solana.ComputeConfig{ComputeLimit: 200_000}` (or another positive limit within the simulator's CU cap).
3. **Handle errors**: Always check errors from constructors and `.Await()`.
4. **Store addresses in config**: Put forwarder and account addresses in `config.staging.json` / `config.production.json`.
5. **`chainSelector` as string in config**: Use `json:"chainSelector,string"` on your config struct to avoid precision loss when unmarshalling `uint64` values from JSON.

## Where to go next

- [Writing to Solana](/cre/guides/workflow/using-solana-client/onchain-write-go) — Full write walkthrough (deploy, broadcast, production forwarder addresses)
- [Solana Client SDK Reference](/cre/reference/sdk/solana-client-go) — Full API reference for `solana.Client` and helper functions