Skip to content

DaviRain-Su/solana-program-sdk-zig

 
 

Repository files navigation

solana-program-sdk-zig

Complete Zig implementation of the Solana SDK, enabling Solana blockchain development in Zig.

This project provides a comprehensive, type-safe Zig SDK that mirrors the Rust solana-sdk crate, allowing developers to build Solana programs and clients using Zig's modern, memory-safe language.

Features

  • Complete Solana SDK Implementation - Full feature parity with Rust solana-sdk
  • Native SBF Support - solana-zig compiles directly to Solana BPF target
  • Type-Safe API - Zero-cost abstractions matching Rust SDK
  • Two-Layer Architecture - Shared SDK types + Program SDK with syscalls

Token-2022 Support

Feature Status
SPL Token (Original) ✅ Complete (v2.0.0)
Associated Token Account ✅ Complete (v2.0.0)
Token-2022 Extensions ⏳ Planned (v2.1.0)

See docs/TOKEN_PROGRAMS.md for details.

Architecture

Build Pipeline

┌─────────────┐                    ┌─────────────┐
│   Zig Code  │───────────────────>│ Solana eBPF │
│             │    solana-zig      │   (.so)     │
└─────────────┘                    └─────────────┘

Module Structure

solana-program-sdk-zig/
├── sdk/                    # Shared SDK (no syscalls)
│   └── src/
│       ├── public_key.zig  # PublicKey type (pure SHA256 PDA)
│       ├── hash.zig        # Hash type
│       ├── signature.zig   # Signature type
│       ├── keypair.zig     # Keypair type
│       ├── instruction.zig # Instruction types (no CPI)
│       ├── bincode.zig     # Bincode serialization
│       ├── borsh.zig       # Borsh serialization
│       └── ...
├── src/                    # Program SDK (with syscalls)
│   ├── public_key.zig      # Re-exports SDK + syscall PDA
│   ├── instruction.zig     # Re-exports SDK + CPI
│   ├── account.zig         # Account types
│   ├── syscalls.zig        # Solana syscalls
│   ├── entrypoint.zig      # Program entrypoint
│   ├── log.zig             # Logging
│   └── ...
├── anchor/                 # Anchor framework subpackage
│   └── src/
│       └── root.zig
├── program-test/           # Integration tests
└── build.zig

Anchor Framework

The Anchor-like framework is now a dedicated subpackage under anchor/.

const anchor = @import("sol_anchor_zig");
const sol = anchor.sdk;

IDL + Zig client codegen:

const idl_json = try anchor.generateIdlJson(allocator, MyProgram, .{});
const client_src = try anchor.generateZigClient(allocator, MyProgram, .{});

IDL output (build step):

./solana-zig/zig build idl \
  -Didl-program=anchor/src/idl_example.zig \
  -Didl-output-dir=idl

idl-program must export pub const Program. By default, the IDL file name is derived from the program metadata name (or the program type name) and written under idl/. Use -Didl-output to override the full path.

Comptime derives:

const Accounts = anchor.Accounts(struct {
    authority: anchor.Signer,
    counter: anchor.Account(CounterData, .{
        .discriminator = anchor.accountDiscriminator("Counter"),
        .attrs = &.{
            anchor.attr.seeds(&.{ anchor.seed("counter"), anchor.seedAccount("authority") }),
            anchor.attr.bump(),
            anchor.attr.constraint("authority.key() == counter.authority"),
        },
    }),
});

const AccountsSugar = anchor.Accounts(struct {
    authority: anchor.Signer,
    counter: anchor.Account(CounterData, .{
        .discriminator = anchor.accountDiscriminator("Counter"),
        .attrs = anchor.attr.account(.{
            .seeds = &.{ anchor.seed("counter"), anchor.seedAccount("authority") },
            .seeds_program = anchor.seedAccount("authority"),
            .bump_field = "bump",
            .constraint = "authority.key() == counter.authority",
        }),
    }),
});

const AccountsTyped = anchor.Accounts(struct {
    authority: anchor.Signer,
    counter: anchor.Account(CounterData, .{
        .discriminator = anchor.accountDiscriminator("Counter"),
        .attrs = anchor.attr.account(.{
            .mut = true,
            .signer = true,
            .seeds = &.{ anchor.seed("counter"), anchor.seedAccount("authority") },
            .bump_field = "bump",
            .owner_expr = "authority.key()",
            .space_expr = "8 + INIT_SPACE",
            .constraint = "authority.key() == counter.authority",
        }),
    }),
});

const CounterTyped = anchor.Account(CounterData, .{
    .discriminator = anchor.accountDiscriminator("Counter"),
    .bump_field = anchor.dataField(CounterData, .bump),
    .seeds = &.{
        anchor.seed("counter"),
        anchor.seedDataField(CounterData, .authority),
    },
});

const FieldAccounts = anchor.AccountsWith(struct {
    authority: anchor.Signer,
    counter: CounterTyped,
}, .{
    .counter = anchor.attr.account(.{
        .mut = true,
        .signer = true,
    }),
});

const FieldAccountsDerive = anchor.AccountsDerive(struct {
    authority: anchor.Signer,
    counter: CounterTyped,
    pub const attrs = .{
        .counter = anchor.attr.account(.{
            .mut = true,
            .signer = true,
        }),
    };
});

const TokenAccounts = anchor.Accounts(struct {
    payer: anchor.SignerMut,
    authority: anchor.Signer,
    mint: *const anchor.sdk.account.Account.Info,
});

const TokenAccountWrapped = anchor.AccountField(CounterTyped, &.{
    anchor.attr.initIfNeeded(),
    anchor.attr.payer(anchor.accountField(TokenAccounts, .payer)),
    anchor.attr.tokenMint(anchor.accountField(TokenAccounts, .mint)),
    anchor.attr.tokenAuthority(anchor.accountField(TokenAccounts, .authority)),
    anchor.attr.associatedTokenMint(anchor.accountField(TokenAccounts, .mint)),
    anchor.attr.associatedTokenAuthority(anchor.accountField(TokenAccounts, .authority)),
});

const CounterEvent = anchor.Event(struct {
    amount: anchor.eventField(u64, .{ .index = true }),
    owner: sol.PublicKey,
});

Build/tests for anchor:

cd anchor
../solana-zig/zig build test --summary all

Prerequisites

solana-zig (Required)

./install-solana-zig.sh

# Or set custom version
SOLANA_ZIG_VERSION=v1.52.0 ./install-solana-zig.sh

solana-zig is a modified Zig compiler with native Solana SBF target support. It compiles directly to .so files without external linkers.

For Deployment (Optional)

# Solana CLI
sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"

Quick Start

1. Building On-Chain Programs

// src/main.zig
const sdk = @import("solana_program_sdk");

fn processInstruction(
    program_id: *sdk.PublicKey,
    accounts: []sdk.Account,
    data: []const u8,
) sdk.ProgramResult {
    sdk.log.sol_log("Hello from Zig!");
    return .ok;
}

comptime {
    sdk.entrypoint.define(processInstruction);
}
# Build for Solana
./solana-zig/zig build -Dtarget=sbf-solana

2. Using SDK Types (Off-Chain)

const sdk = @import("solana_sdk");

pub fn main() !void {
    const pubkey = try sdk.PublicKey.fromBase58("11111111111111111111111111111112");
    const keypair = sdk.Keypair.generate();
    
    std.debug.print("Public key: {s}\n", .{pubkey.toBase58()});
}

Testing

# Test Program SDK
./solana-zig/zig build test --summary all

# Integration tests
./program-test/test.sh

Shared SDK types now live in the external repo DaviRain-Su/solana-sdk-zig; run its tests there if needed.

See docs/TESTING.md for the full test matrix.

Testing with MCL (Optional)

For off-chain BN254 elliptic curve operations:

git submodule update --init vendor/mcl
./solana-zig/zig build test -Dwith-mcl

MCL is optional. On-chain programs use Solana's native syscalls (sol_alt_bn128_*).

Deployment

Build for Solana SBF and deploy with Solana CLI. See docs/DEPLOYMENT.md for step-by-step workflows.

./solana-zig/zig build -Dtarget=sbf-solana

Development Status

See ROADMAP.md for current implementation status.

License

MIT

About

Write Solana programs in Zig.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Zig 83.4%
  • Rust 16.3%
  • Shell 0.3%