solana-haskell-sdk: Solana SDK: transaction building, signing, program clients, and JSON-RPC.

[ apache, blockchain, library, program, solana, web3 ] [ Propose Tags ] [ Report a vulnerability ]

This library includes features like key generation and management, transaction and instruction construction, and a JSON-RPC API client.

This library is aimed at developers building Solana dApps, tools, or infrastructure in Haskell.

All serialization is verified byte-for-byte against the official Rust SDK by golden-vector tests.


[Skip to Readme]

Flags

Manual Flags

NameDescriptionDefault
integration

Build the local-validator integration test suite. Off by default so that building this package's tests needs no WebSocket dependency and no running validator; see the Integration tests section of the README.

Disabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 1.2.0.0
Change log CHANGELOG.md
Dependencies aeson (>=2.2 && <2.3), base (>=4.18.0.0 && <4.19), base58-bytestring (>=0.1 && <0.2), base64 (>=1.0 && <1.1), binary (>=0.8 && <0.9), bytestring (>=0.11 && <0.12), containers (>=0.6 && <0.7), crypton (>=1.0 && <1.1), ed25519 (>=0.0.5 && <0.1), either (>=5.0 && <5.1), extra (>=1.8 && <1.9), jsonrpc-tinyclient (>=1.1 && <1.2), memory (>=0.18 && <0.19), mtl (>=2.3 && <2.4), solana-haskell-sdk, text (>=2.0 && <2.1), vector (>=0.13 && <0.14), web3 (>=1.1 && <1.2), web3-provider (>=1.1 && <1.2) [details]
Tested with ghc ==9.6.7
License Apache-2.0
Copyright 2024 Marius Georgescu
Author Marius Georgescu
Maintainer georgescumarius@live.com
Uploaded by mariusgeorgescu at 2026-08-11T13:47:16Z
Category Blockchain, Web3, Solana
Home page https://github.com/mariusgeorgescu/solana-haskell-sdk
Bug tracker https://github.com/mariusgeorgescu/solana-haskell-sdk/issues
Source repo head: git clone https://github.com/mariusgeorgescu/solana-haskell-sdk
Distributions
Executables solana-haskell-sdk
Downloads 0 total (0 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for solana-haskell-sdk-1.2.0.0

[back to package description]

Solana Haskell SDK Logo

Solana SDK library for Haskellers

Table of contents

Documentation

API documentation is generated with Haddock (cabal haddock). Serialization correctness methodology: every instruction, message, and transaction encoder is asserted byte-identical to vectors generated from the official Rust crates (solana-sdk, spl-token, mpl-token-metadata) โ€” see tools/README.md.

Integration tests

An opt-in test suite runs the SDK against a local validator. It sits behind the integration cabal flag, so a plain cabal test all neither builds it nor pulls its extra dependencies:

solana-test-validator --reset
cabal test integration-tests --flags=integration

Without a validator listening on 127.0.0.1:8899 the suite skips itself and exits 0, so it stays green in CI even when enabled. Set SOLANA_INTEGRATION=1 to make an unreachable validator a failure instead, or SOLANA_RPC_URL to target a different endpoint.

WebSocket subscriptions

Network.Solana.RPC.WebSocket speaks Solana's PubSub protocol: signature and account subscriptions, and awaitSignature, which waits for a transaction to be pushed to you instead of polling for it.

The module is transport-agnostic, so the SDK carries no WebSocket dependency and the same code serves plain ws:// and TLS wss:// endpoints โ€” you supply the connection. With the websockets package:

import Network.Solana.RPC.WebSocket
import Network.WebSockets qualified as WS

WS.runClient "127.0.0.1" 8900 "/" $ \conn -> do
  let transport = WsTransport (WS.sendTextData conn) (WS.receiveData conn)
  result <- awaitSignature transport (RequestId 1) (Just "confirmed") 30 signature
  print result   -- Right <slot>, or Left with the on-chain or protocol error

For wss:// endpoints use wuss's runSecureClient in place of runClient; nothing else changes.

Features

  • Full JSON-RPC API client (accounts, blocks, chain, ledger, tokens, tokenomics, transactions)
  • Wallet, account and keys management (ed25519 keypairs, base58 addresses)
  • Program Derived Addresses (findProgramAddress / createProgramAddress)
  • Transaction building, signing and submission
    • Priority fees via Compute Budget (setComputeUnitLimit, setComputeUnitPrice)
    • Versioned (v0) transactions and Address Lookup Tables
    • Clients for native programs
      • Address Lookup Table
      • BPF Loader (upgradeable)
      • Compute Budget
      • Secp256k1 (instruction construction; signing out of scope)
      • Stake (delegation lifecycle; seed-authority variants out of scope)
      • System Program (all 13 instructions)
      • Vote (account management)
    • Clients for Solana Program Library (SPL)
      • Memo
      • SPL Token (instructions 0-20, incl. transferChecked)
      • Associated Token Account (derive + create, idempotent variant)
    • Metaplex Token Metadata (create/update metadata, master edition)
  • On-chain account state decoders (SPL token accounts and mints, lookup tables, stake and nonce accounts, Metaplex metadata)
  • PubSub (WebSocket) signature and account subscriptions, with push-based confirmation
  • Serialization verified byte-for-byte against the official Rust crates (solana-sdk, spl-token, mpl-token-metadata) (golden-vector tests)

Release status

The current stable release is v1.2.0.0. Serialization is verified byte-for-byte against the official Rust SDK by golden-vector tests (see test/fixtures/ and tools/README.md).

Usage Examples

Simple transfer

This example demonstrates how to use the Haskell Solana SDK to interact with a Solana validator and perform basic blockchain operations such as keypair generation, account funding via airdrop, balance checking, and transferring SOL tokens.

In the provided sample:

  1. We start by generating a new keypair to act as the transaction sender and fee payer.

  2. We connect to a local Solana validator using an HTTP provider.

  3. The newly generated keypair receives an airdrop of 10 SOL to ensure it has sufficient funds.

  4. We define a recipient's public address from a base58 encoded string.

  5. We construct, sign and submit the transaction by defining the signers and the transaction's list of instructions with their parameters.

Before and after performing the transfer of 1 SOL to the recipient, we check and print the account balances to verify the transaction's success.

This straightforward example highlights the convenience and expressiveness of Haskell when building decentralized applications on Solana.

The examples use GHC2021 (this package's default-language). If you compile them under Haskell2010, additionally enable NumericUnderscores and ImportQualifiedPost.

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Monad (void)
import Control.Monad.IO.Class (liftIO)
import Network.Solana.Core.Crypto
import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
import Network.Solana.RPC.HTTP.Transaction
import Network.Solana.SolanaWeb3
import Network.Web3.Provider

main :: IO ()
main = do
  -- Generate keypairs for fee payer (sender)
  (myPublicKey, myPrivateKey) <- createSolanaKeyPair

  -- Create Connection, local validator in this example
  result <- runWeb3' (HttpProvider "http://127.0.0.1:8899") $ do
    -- Fund fee payer
    void $ requestAirdrop myPublicKey 10_000_000_000
    wait 15 -- Wait 15 seconds be sure the tx was confirmed

    -- Define recipient's address from a base58-encoded string
    let recipient = "A988FuUtUVk8jMUuVc1ccaoTA3VS9CB4dkEf9XUAUqV4"

    -- Check balance
    printBalances [myPublicKey, recipient]

    -- Create a new transaction.
    txId <-
      newTransaction
        [myPrivateKey] -- Signing keys (with all required signers)
        -- List of instructions
        [ SystemProgram.transfer
            myPublicKey -- sender address
            recipient -- recipient address
            1_000_000_000 -- amount to transfer 1 SOL
        ]
    liftIO $ putStrLn ("Transaction sent: " <> show txId)

    void $ confirmTransaction txId
    -- Check balance
    printBalances [myPublicKey, recipient]

  either (\e -> putStrLn ("RPC error: " <> show e)) pure result

SPL token transfer (Associated Token Accounts)

Tokens live in associated token accounts (ATAs) โ€” program-derived addresses computed from the wallet and the mint. This example derives both ATAs with getAssociatedTokenAddress, creates the recipient's ATA if missing (idempotent, safe to include unconditionally), and moves tokens with the decimals-checked transferChecked.

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Monad (void)
import Data.Maybe (fromJust)
import Network.Solana.Core.Crypto
import Network.Solana.SolanaWeb3
import Network.Solana.SplPrograms.AssociatedTokenAccount qualified as Ata
import Network.Solana.SplPrograms.Token qualified as Token
import Network.Web3.Provider

main :: IO ()
main = do
  (myPublicKey, myPrivateKey) <- createSolanaKeyPair

  void $ runWeb3' (HttpProvider "http://127.0.0.1:8899") $ do
    let mint = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" -- the token's mint address
        recipient = "A988FuUtUVk8jMUuVc1ccaoTA3VS9CB4dkEf9XUAUqV4" -- recipient wallet

        -- ATAs are PDAs of (wallet, token program, mint): derived, not generated.
        sourceAta = fromJust (Ata.getAssociatedTokenAddress myPublicKey mint)
        destinationAta = fromJust (Ata.getAssociatedTokenAddress recipient mint)

    void $
      newTransaction
        [myPrivateKey]
        [ -- Create the recipient's token account if it does not exist yet (no-op otherwise).
          Ata.createAssociatedTokenAccountIdempotent
            myPublicKey -- funder (pays rent)
            recipient -- wallet that will own the ATA
            mint,
          -- Transfer 1 token (here: 6 decimals); mint and decimals are verified on-chain.
          Token.transferChecked
            sourceAta -- source token account
            mint -- token mint
            destinationAta -- destination token account
            myPublicKey -- owner of the source account
            [] -- extra multisig signers (none)
            1_000_000 -- amount in base units
            6 -- decimals of the mint
        ]

Priority fees and memo

Compute Budget instructions raise a transaction's scheduling priority by paying a fee per compute unit; a memo attaches a signed, human-readable note recorded on-chain. Both are ordinary Instructions added to the same instruction list.

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Monad (void)
import Network.Solana.Core.Crypto
import Network.Solana.NativePrograms.ComputeBudget qualified as ComputeBudget
import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
import Network.Solana.SolanaWeb3
import Network.Solana.SplPrograms.Memo qualified as Memo
import Network.Web3.Provider

main :: IO ()
main = do
  (myPublicKey, myPrivateKey) <- createSolanaKeyPair

  void $ runWeb3' (HttpProvider "http://127.0.0.1:8899") $ do
    let recipient = "A988FuUtUVk8jMUuVc1ccaoTA3VS9CB4dkEf9XUAUqV4"

    void $
      newTransaction
        [myPrivateKey]
        [ ComputeBudget.setComputeUnitLimit 200_000, -- cap the compute units this tx may use
          ComputeBudget.setComputeUnitPrice 10_000, -- priority fee: micro-lamports per compute unit
          SystemProgram.transfer myPublicKey recipient 1_000_000_000, -- 1 SOL
          Memo.buildMemo "thanks for the coffee" [myPublicKey] -- signed on-chain note
        ]

Contributing

We welcome all contributors! See contributing guide for how to get started.

Credits

Created and maintained by Marius Georgescu.

License

Apache-2.0