packages feed

solana-haskell-sdk-1.3.0.0: CHANGELOG.md

# Revision history for solana-haskell-sdk

## 1.3.0.0 -- 2026-09-13

* Fixed (security): `readSigningKeyFromFile` accepted key files of any length
  and silently wrapped out-of-range values, producing a malformed
  `SolanaPrivateKey` whose use in `dsign`/`sign` read past the end of the key
  buffer in the ed25519 C code. The loader now decodes the file as a JSON
  array of exactly 64 bytes and verifies the public-key half against the seed
  (as `solana-sdk`'s `Keypair::from_bytes` does), throwing an `IOError`
  otherwise.
* Added `mkPrivateKeyFromBytes`, a total constructor performing those checks
  on raw bytes.
* Changed: `unsafeSolanaPublicKeyRaw` and `unsafeSolanaPrivateKeyRaw` now call
  `error` unless given exactly 32 / 64 bytes, matching the other `unsafe*`
  constructors; `mkPrivateKeyFromString` (and so `unsafeSolanaPrivateKey`)
  applies the same public-key-half check as `mkPrivateKeyFromBytes`.
* Changed (breaking): `SolanaPublicKey`, `SolanaPrivateKey` and
  `SolanaSignature` no longer derive `Generic`, which let generic code build
  unchecked values behind the abstract constructors.
* Fixed: `newTransaction` now names its first signing key as the fee payer
  (via `newTransactionIntentWithPayer`), so transactions whose only signer is
  a read-only authority -- a memo-only transaction, or a standalone SPL
  `mintTo`/`transferChecked` -- are no longer rejected by the node with
  "Transaction failed to sanitize accounts offsets correctly". The first key
  is forced writable and pinned to account 0 even if no instruction
  references it (sponsored fees), the remaining keys may be passed in any
  order, an empty key list throws `userError`, and an unused key is reported
  as a `CompileException` before the send. Output is byte-identical for every
  transaction that was already valid.
* Added `compileV0MessageWithPayer` and `newV0TransactionIntentWithPayer`,
  the explicit-fee-payer counterparts of the v0 compiler and signer
  (mirroring the Rust SDK's `v0::Message::try_compile(payer, ..)`), plus
  `mkNewMessageWithPayer` and `orderSigningKeys` as exported building blocks.
* Fixed: `newNonceTransaction` now submits with `preflightCommitment =
  "confirmed"` (new `cfgNonceSendConfirmed`), matching the commitment it reads
  the nonce account at. Previously the node's default `finalized` preflight
  rejected the send with `BlockhashNotFound` whenever the nonce account had
  been created or advanced within the last ~32 slots -- i.e. on every
  back-to-back use -- unless the caller first waited for finalization.
* Fixed: `AccountData`'s `FromJSON` decoded a bare `data` string as (lenient)
  base64. Per the RPC account-data format a bare string is the node's legacy
  `binary` encoding, i.e. base58, so `getAccountInfo'`, `getProgramAccounts'`
  and `getTokenAccountsByOwner'`/`ByDelegate'` called with a configuration
  that omits `encoding` (or sets `"binary"`), and `getMultipleAccounts'` with
  `"binary"`, returned silently corrupted bytes for accounts of up to 128
  bytes. Bare strings now decode strictly as
  base58 (invalid input is a parse error) and `AccountData` round-trips
  through its own `ToJSON`; the `[data, "base64"]` form and the
  base64-requesting wrappers are unchanged.
* Fixed: `AccountData` now parses the `{program, parsed, space}` object a
  node returns for `encoding: "jsonParsed"` when it has a parser for the
  owner program (nonce, SPL Token, stake, vote, sysvars, ...). Previously
  every such response failed with `parsing AccountDataArray failed, expected
  Array, but encountered Object` through `getAccountInfo'`,
  `getMultipleAccounts'`, `getProgramAccounts'`, `getTokenAccountsByOwner'`
  and `getTokenAccountsByDelegate'`. The base64 pair the node falls back to
  when no parser exists still decodes to `AccountDataBinary`.
* Changed (breaking): `AccountDataJSON` now carries `accDataProgram ::
  String`, `accDataParsed :: Data.Aeson.Value` and `accDataSpace :: Word64`
  instead of `accDataObj :: String`, and its `ToJSON` instance emits the
  node's object. The `["...","json"]` / `["...","jsonParsed"]` pair forms,
  which no node emits, are no longer accepted. `base64+zstd` account data is
  still rejected as unsupported.
* Fixed: `createMasterEditionV3` now marks the metadata account (index 5)
  writable, matching the official `mpl-token-metadata` client. Previously the
  on-chain program silently left `token_standard` un-upgraded
  (`FungibleAsset` instead of `NonFungible`) when the instruction was sent on
  its own. The builder's account metas are now golden-tested against the
  crate (`master-edition-some-accounts`).
* Fixed: `compileInstruction`, and every message compiler built on it
  (`newMessage`, `newTransactionIntent`, `newTransactionIntentWithPayer`, the
  durable-nonce variants, `compileV0Message`, `newV0TransactionIntent`, and
  the `SolanaWeb3` senders), silently wrapped account indices at or past 256
  into the wrong byte, producing a message the node rejects; such messages
  now fail with a `CompileException` (`MissingIndex` carrying an "account
  index overflow" message), mirroring the Rust SDK's
  `CompileError::AccountIndexOverflow`. Messages with up to 256 account keys
  (static plus table-loaded for v0) are unaffected.
* Changed (breaking): `Context.apiVersion` is now `Maybe Text`,
  `PerformanceSample.numNonVoteTransactions` is now `Maybe Word64` and
  `SolanaVersion.feature_set` is now `Maybe Word32`, matching the upstream
  schema where older nodes and some RPC proxies omit `apiVersion` and older
  performance samples report `numNonVoteTransactions` as `null`; previously
  such responses failed to parse.
* WebSocket: a `signatureNotification` whose value lacks the `err` key is now
  rejected by `parseWsMessage` (and reported as `Left` by `awaitSignature`)
  instead of being treated as a successful confirmation.
* Docs: `getBlock`/`getBlock'`/`getBlockTime` now document that skipped,
  pruned and not-yet-available slots are JSON-RPC errors (-32007/-32001/
  -32004) raised as a `JsonRpcException` that `runWeb3'` does not catch,
  rather than `Nothing`; module headers added for `Core.Instruction`,
  `NativePrograms.ComputeBudget`, `NativePrograms.SystemProgram` and
  `SplPrograms.Memo`; the `SolanaWeb3` header reflects the integration suite;
  CONTRIBUTING links defined.
* Added `confirmFinalized` to `SolanaWeb3`: polls `getSignatureStatuses` up
  to 60 s until a signature is `finalized`, throwing on an on-chain error or
  timeout (previously an integration-suite-only helper). Use it before
  `printBalances`/`getBalance`, which read at the node's default `finalized`
  commitment; `confirmTransaction` returns at `confirmed`, so balances read
  right after it can still show pre-transaction state.
* README usage examples are now complete flows that run as-is against
  `solana-test-validator`: payers are funded and finalized, the SPL example
  creates its own mint and token account, and every flow finalizes before
  reading state. The SPL and priority-fee examples are built as the
  `example-spl-transfer` and `example-priority-fee` executables, and a unit
  test keeps the README text identical to them. The README now states that
  the examples also need the `web3-provider` package (`Network.Web3.Provider`)
  in `build-depends`.
* Corrected the 1.2.0.0 note below, which overstated RPC golden-test coverage.
  `tools/rpc-record` now records every RPC method the SDK binds except
  `requestAirdrop`, `sendTransaction` and `simulateTransaction`, aborts
  instead of silently skipping a method the node rejects, and requires
  `solana-test-validator --slots-per-epoch 32` so `getInflationReward` can be
  captured; `Test.RPC.Parsers` now asserts every RPC-layer `FromJSON`
  instance, including default-encoding (base58) and `jsonParsed` account data.
* The integration suite gains cases for the fixes above: memo-only sends
  through `newTransaction` (legacy and v0), the README SPL and priority-fee
  flows, back-to-back durable-nonce use right after a confirmed create or
  advance, default-encoding and `jsonParsed` account reads, and `getBlock` on
  a slot holding no block.

## 1.2.0.0 -- 2026-08-03

* Added on-chain account-state decoders (SPL token accounts and mints, address lookup tables, stake and nonce accounts, Metaplex metadata) with typed SolanaWeb3 fetch helpers; decoded lookup tables feed compileV0Message directly.
* Added developer-experience helpers: explicit fee-payer transactions with automatic signature ordering (sponsored fees supported), a durable-nonce transaction flow, and priority-fee estimation.
* Added an opt-in local-validator integration test suite (`integration-tests`, behind the `integration` cabal flag) covering SOL and sponsored transfers, the SPL token lifecycle, durable nonces, address lookup tables with v0 transactions, priority fees, and WebSocket confirmation; the suite skips itself when no validator is running.
* Added golden tests for the JSON-RPC response parsers, replaying 37 responses recorded from a live validator by `tools/rpc-record` (36 of the SDK's 52 RPC methods; every RPC-layer `FromJSON` instance except `HighestSnapshotSlot`, `PrioritizationFee` and `InflationReward`; account data in `base64` encoding only -- see the 1.3.0.0 entry).
* Added Solana PubSub (WebSocket) support in `Network.Solana.RPC.WebSocket`: signature and account subscribe/unsubscribe requests, notification parsing, and `awaitSignature` — a push-based confirmation that replaces polling. The module is transport-agnostic (`WsTransport`), so the library gains no new dependency and works with both `ws://` and `wss://` endpoints.

## 1.1.0.0 -- 2026-08-01

* Added Metaplex Token Metadata client (CreateMetadataAccountV3, UpdateMetadataAccountV2, CreateMasterEditionV3) with metadata/master-edition PDA derivation, built on a new minimal Borsh serialization layer.
* Added Address Lookup Table program client and versioned (v0) transaction support: compile messages against lookup tables and sign VersionedTransactions (encode-only; account-state parsing out of scope). The `CompileException` constructor (`MissingIndex`) is now exported for error inspection.
* Hackage-ready packaging: PVP upper bounds on all dependencies; homepage and bug-reports metadata.

## 1.0.0.0 -- 2026-08-01

First stable release: byte-verified clients for System, Compute Budget, Stake, Vote, BPF Loader (upgradeable), Secp256k1, SPL Memo, SPL Token, and Associated Token Account programs; PDA derivation; canonical Rust-identical message compilation.

* Changed: `sendTransaction`'s default configuration no longer skips preflight
  simulation and no longer caps retries — submissions now follow the node's
  defaults (preflight runs; the node rebroadcasts until blockhash expiry).
  Transactions failing simulation return an RPC error instead of a signature.
* Changed: account-fetching RPC methods now request `base64` encoding
  explicitly for reliable binary account data.
* Hardened all RPC-facing JSON parsers to be total: malformed or unexpected
  node responses (failed transactions, v0 transactions, pruned/unknown slots)
  no longer crash the client.
* Fixed: `mkPrivateKeyFromString` rejected valid 64-byte private keys; now
  parses them correctly.
* Fixed: `BlockHash` and `CompactArray` `Binary` decoding were asymmetric
  with their `put` (falling back to an incompatible/length-prefixed
  decoder); both now round-trip correctly.
* Fixed documentation typos referring to the `RPCResponse` type (the
  exported name never changed) and renamed RPC fields for consistency
  (`Ammount*` -> `Amount*`); changed transaction/account error fields to
  structured `Maybe Value` instead of partial `Maybe String`.
* Renamed `ClusterNodes.sharedVersion` to `shredVersion` (typo fix; matches
  the RPC field).
* Added `confirmTransaction` to `SolanaWeb3`: polls for `confirmed`/
  `finalized` status instead of a fixed `wait`.
* Haddock coverage completed for the Core, RPC/HTTP, and SolanaWeb3 modules
  touched by the quality pass (module headers and per-export documentation);
  `cabal haddock` exits 0 with a handful of internal native/SPL-program
  helpers still undocumented.
* Added upgradeable BPF loader client (buffer/write/deploy/upgrade/authority/
  close/extend) with program-data address derivation.
* Added secp256k1 precompile client: signature-verification instruction
  construction from a precomputed signature (signing is out of scope).
* Added Stake program client (initialize, authorize, delegate, split, withdraw,
  deactivate, lockup, merge, checked variants) — golden-tested against the Rust SDK.
* Added Vote program client (account management: initialize, authorize, withdraw,
  identity/commission updates); consensus voting instructions are out of scope.
* Added SPL Token program client (instructions 0-20: mint/account initialization,
  transfers, approvals, minting, burning, freezing, multisig support) —
  golden-tested against the `spl-token` Rust crate.
* Added Associated Token Account program client with address derivation.
* Added Program Derived Address (PDA) support: `createProgramAddress` /
  `findProgramAddress` with ed25519 on-curve rejection (new `crypton` and `memory` dependencies).
* Added Compute Budget program client: request heap frame, set compute unit
  limit, set compute unit price (priority fees), set loaded accounts data size
  limit — golden-tested against the Rust SDK.
* Added SPL Memo (v2) program client.
* Added binary decoding for `SystemInstruction` and `ComputeBudgetInstruction`
  (symmetric `Binary` instances, round-trip tested).
* Fixed: account keys within each privilege section are now ordered
  canonically (sorted by pubkey, fee payer first) to match the Rust SDK, so
  multi-program messages serialize byte-identically. For multi-signer
  transactions, signing keys must be passed in the canonical account order
  (fee payer first).
* Test suite: golden vectors generated from the Rust `solana-sdk` (byte-for-byte
  serialization checks at instruction, message, and signed-transaction level),
  plus QuickCheck properties for compact-u16, crypto round-trips, and message
  header/key-ordering invariants.
* Fixed: pubkeys inside System Program instruction data were serialized with a
  length prefix (invalid wire format).
* Fixed: `CreateAccountWithSeed` seed was missing its u64 length prefix.
* Fixed: `SolanaSignature` binary decoding read 32 bytes instead of 64.
* Fixed: the program id was appended as an extra account to every instruction;
  it is now added only to the message account keys.
* Fixed: account privilege deduplication in message building used the wrong
  buckets to decide writability, producing duplicate keys or wrongly-writable
  accounts when the same account appeared in several instructions with mixed
  privileges.
* Fixed: compact-u16 decoding now rejects aliased (non-canonical) encodings.
* Fixed: `CompiledInstruction` JSON parsing fails cleanly on invalid base58.
* Added the 9 remaining System Program instructions: nonce account management
  (advance, withdraw, initialize, authorize, upgrade) and
  allocate/assign/transfer with seed.
* Added CI (GitHub Actions).

## 0.1.0.0 -- 2024 (unreleased alpha)

* Initial alpha: JSON-RPC API client, key management, System Program transfers.