diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,131 @@
 # 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`, so every `FromJSON` instance is asserted against JSON a node actually sends.
+* 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
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -86,7 +86,7 @@
 
 ### 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](https://github.com/mariusgeorgescu/solana-haskell-sdk/blob/main/tools/README.md)).
+The current stable release is **v1.3.0.0**. Serialization is verified byte-for-byte against the official Rust SDK by golden-vector tests (see test/fixtures/ and [tools/README.md](https://github.com/mariusgeorgescu/solana-haskell-sdk/blob/main/tools/README.md)).
 
 ## Usage Examples
 
@@ -100,24 +100,25 @@
 
 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.
+3. The newly generated keypair receives an airdrop of 10 SOL, and we wait for it to be finalized (later sends are simulated against the finalized bank).
 
 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.
+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. The second read happens after waiting for the transfer to finalize: `getBalance` reads at the node's default commitment, `finalized`, so a balance read right after a merely `confirmed` transaction would still show the old value.
 
 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`.
 
+> The programs need `solana-haskell-sdk` and `web3-provider` (the package providing `Network.Web3.Provider`, i.e. `runWeb3'` and `HttpProvider`) in `build-depends`. RPC failures such as a rejected preflight simulation are raised as a `JsonRpcException` from `runWeb3'`, not returned as `Left`. Each example is also built as an executable of this package (`solana-haskell-sdk`, `example-spl-transfer`, `example-priority-fee`) and runs as-is against `solana-test-validator`.
+
 ```haskell
 {-# 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
@@ -132,9 +133,9 @@
 
   -- 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
+    -- Fund the fee payer and wait until the airdrop is finalized: sends are
+    -- preflighted against the finalized bank, and balances are read there too
+    requestAirdrop myPublicKey 10_000_000_000 >>= confirmFinalized
 
     -- Define recipient's address from a base58-encoded string
     let recipient = "A988FuUtUVk8jMUuVc1ccaoTA3VS9CB4dkEf9XUAUqV4"
@@ -145,7 +146,7 @@
     -- Create a new transaction.
     txId <-
       newTransaction
-        [myPrivateKey] -- Signing keys (with all required signers)
+        [myPrivateKey] -- Signing keys (the first key pays the fee)
         -- List of instructions
         [ SystemProgram.transfer
             myPublicKey -- sender address
@@ -154,8 +155,9 @@
         ]
     liftIO $ putStrLn ("Transaction sent: " <> show txId)
 
-    void $ confirmTransaction txId
-    -- Check balance
+    -- Wait for finalization (throws if the transaction failed on-chain or
+    -- timed out), so the balances below reflect the transfer
+    confirmFinalized txId
     printBalances [myPublicKey, recipient]
 
   either (\e -> putStrLn ("RPC error: " <> show e)) pure result
@@ -163,16 +165,19 @@
 
 ### 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`.
+Tokens live in *associated token accounts* (ATAs) — program-derived addresses computed from the wallet and the mint. This example first creates a mint and funds the sender's token account (so it runs as-is against a local validator), then 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`.
 
 ```haskell
 {-# LANGUAGE OverloadedStrings #-}
 
 module Main where
 
-import Control.Monad (void)
+import Control.Monad.IO.Class (liftIO)
 import Data.Maybe (fromJust)
 import Network.Solana.Core.Crypto
+import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
+import Network.Solana.RPC.HTTP.Tokenomics (getMinimumBalanceForRentExemption)
+import Network.Solana.RPC.HTTP.Transaction (requestAirdrop)
 import Network.Solana.SolanaWeb3
 import Network.Solana.SplPrograms.AssociatedTokenAccount qualified as Ata
 import Network.Solana.SplPrograms.Token qualified as Token
@@ -181,24 +186,41 @@
 main :: IO ()
 main = do
   (myPublicKey, myPrivateKey) <- createSolanaKeyPair
+  (mint, mintPrivateKey) <- createSolanaKeyPair -- the new token's mint account
 
-  void $ runWeb3' (HttpProvider "http://127.0.0.1:8899") $ do
-    let mint = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" -- the token's mint address
-        recipient = "A988FuUtUVk8jMUuVc1ccaoTA3VS9CB4dkEf9XUAUqV4" -- recipient wallet
+  result <- runWeb3' (HttpProvider "http://127.0.0.1:8899") $ do
+    requestAirdrop myPublicKey 10_000_000_000 >>= confirmFinalized
 
+    let 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 $
+    -- Setup: create a mint with 6 decimals (we are its mint authority), our own
+    -- token account, and mint 10 tokens into it. The mint keypair co-signs
+    -- because createAccount requires the new account's signature.
+    mintRent <- getMinimumBalanceForRentExemption 82 -- a mint account is 82 bytes
+    setupTx <-
       newTransaction
+        [myPrivateKey, mintPrivateKey]
+        [ SystemProgram.createAccount myPublicKey mint mintRent 82 Token.tokenProgramId,
+          Token.initializeMint2 mint 6 myPublicKey Nothing,
+          Ata.createAssociatedTokenAccount myPublicKey myPublicKey mint,
+          Token.mintTo mint sourceAta myPublicKey [] 10_000_000
+        ]
+    confirmFinalized setupTx
+
+    -- Transfer 1 token to the recipient
+    transferTx <-
+      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.
+          -- Transfer 1 token (6 decimals); mint and decimals are verified on-chain.
           Token.transferChecked
             sourceAta -- source token account
             mint -- token mint
@@ -208,21 +230,28 @@
             1_000_000 -- amount in base units
             6 -- decimals of the mint
         ]
+    confirmFinalized transferTx
+
+    -- Read back the recipient's token account (decoded on-chain state)
+    account <- getTokenAccount destinationAta
+    liftIO $ putStrLn ("Recipient token balance: " <> show (Token.taAmount <$> account))
+
+  either (\e -> putStrLn ("RPC error: " <> show e)) pure result
 ```
 
 ### 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 `Instruction`s added to the same instruction list.
+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 `Instruction`s added to the same instruction list. The payer is funded first.
 
 ```haskell
 {-# 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.RPC.HTTP.Transaction (requestAirdrop)
 import Network.Solana.SolanaWeb3
 import Network.Solana.SplPrograms.Memo qualified as Memo
 import Network.Web3.Provider
@@ -231,10 +260,12 @@
 main = do
   (myPublicKey, myPrivateKey) <- createSolanaKeyPair
 
-  void $ runWeb3' (HttpProvider "http://127.0.0.1:8899") $ do
+  result <- runWeb3' (HttpProvider "http://127.0.0.1:8899") $ do
+    requestAirdrop myPublicKey 10_000_000_000 >>= confirmFinalized
+
     let recipient = "A988FuUtUVk8jMUuVc1ccaoTA3VS9CB4dkEf9XUAUqV4"
 
-    void $
+    txId <-
       newTransaction
         [myPrivateKey]
         [ ComputeBudget.setComputeUnitLimit 200_000, -- cap the compute units this tx may use
@@ -242,6 +273,10 @@
           SystemProgram.transfer myPublicKey recipient 1_000_000_000, -- 1 SOL
           Memo.buildMemo "thanks for the coffee" [myPublicKey] -- signed on-chain note
         ]
+    confirmFinalized txId
+    printBalances [recipient]
+
+  either (\e -> putStrLn ("RPC error: " <> show e)) pure result
 ```
 
 ## Contributing
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -2,7 +2,6 @@
 
 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
@@ -17,9 +16,9 @@
 
   -- 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
+    -- Fund the fee payer and wait until the airdrop is finalized: sends are
+    -- preflighted against the finalized bank, and balances are read there too
+    requestAirdrop myPublicKey 10_000_000_000 >>= confirmFinalized
 
     -- Define recipient's address from a base58-encoded string
     let recipient = "A988FuUtUVk8jMUuVc1ccaoTA3VS9CB4dkEf9XUAUqV4"
@@ -30,7 +29,7 @@
     -- Create a new transaction.
     txId <-
       newTransaction
-        [myPrivateKey] -- Signing keys (with all required signers)
+        [myPrivateKey] -- Signing keys (the first key pays the fee)
         -- List of instructions
         [ SystemProgram.transfer
             myPublicKey -- sender address
@@ -39,8 +38,9 @@
         ]
     liftIO $ putStrLn ("Transaction sent: " <> show txId)
 
-    void $ confirmTransaction txId
-    -- Check balance
+    -- Wait for finalization (throws if the transaction failed on-chain or
+    -- timed out), so the balances below reflect the transfer
+    confirmFinalized txId
     printBalances [myPublicKey, recipient]
 
   either (\e -> putStrLn ("RPC error: " <> show e)) pure result
diff --git a/app/PriorityFee.hs b/app/PriorityFee.hs
new file mode 100644
--- /dev/null
+++ b/app/PriorityFee.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Network.Solana.Core.Crypto
+import Network.Solana.NativePrograms.ComputeBudget qualified as ComputeBudget
+import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
+import Network.Solana.RPC.HTTP.Transaction (requestAirdrop)
+import Network.Solana.SolanaWeb3
+import Network.Solana.SplPrograms.Memo qualified as Memo
+import Network.Web3.Provider
+
+main :: IO ()
+main = do
+  (myPublicKey, myPrivateKey) <- createSolanaKeyPair
+
+  result <- runWeb3' (HttpProvider "http://127.0.0.1:8899") $ do
+    requestAirdrop myPublicKey 10_000_000_000 >>= confirmFinalized
+
+    let recipient = "A988FuUtUVk8jMUuVc1ccaoTA3VS9CB4dkEf9XUAUqV4"
+
+    txId <-
+      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
+        ]
+    confirmFinalized txId
+    printBalances [recipient]
+
+  either (\e -> putStrLn ("RPC error: " <> show e)) pure result
diff --git a/app/SplTransfer.hs b/app/SplTransfer.hs
new file mode 100644
--- /dev/null
+++ b/app/SplTransfer.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Control.Monad.IO.Class (liftIO)
+import Data.Maybe (fromJust)
+import Network.Solana.Core.Crypto
+import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
+import Network.Solana.RPC.HTTP.Tokenomics (getMinimumBalanceForRentExemption)
+import Network.Solana.RPC.HTTP.Transaction (requestAirdrop)
+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
+  (mint, mintPrivateKey) <- createSolanaKeyPair -- the new token's mint account
+
+  result <- runWeb3' (HttpProvider "http://127.0.0.1:8899") $ do
+    requestAirdrop myPublicKey 10_000_000_000 >>= confirmFinalized
+
+    let 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)
+
+    -- Setup: create a mint with 6 decimals (we are its mint authority), our own
+    -- token account, and mint 10 tokens into it. The mint keypair co-signs
+    -- because createAccount requires the new account's signature.
+    mintRent <- getMinimumBalanceForRentExemption 82 -- a mint account is 82 bytes
+    setupTx <-
+      newTransaction
+        [myPrivateKey, mintPrivateKey]
+        [ SystemProgram.createAccount myPublicKey mint mintRent 82 Token.tokenProgramId,
+          Token.initializeMint2 mint 6 myPublicKey Nothing,
+          Ata.createAssociatedTokenAccount myPublicKey myPublicKey mint,
+          Token.mintTo mint sourceAta myPublicKey [] 10_000_000
+        ]
+    confirmFinalized setupTx
+
+    -- Transfer 1 token to the recipient
+    transferTx <-
+      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 (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
+        ]
+    confirmFinalized transferTx
+
+    -- Read back the recipient's token account (decoded on-chain state)
+    account <- getTokenAccount destinationAta
+    liftIO $ putStrLn ("Recipient token balance: " <> show (Token.taAmount <$> account))
+
+  either (\e -> putStrLn ("RPC error: " <> show e)) pure result
diff --git a/solana-haskell-sdk.cabal b/solana-haskell-sdk.cabal
--- a/solana-haskell-sdk.cabal
+++ b/solana-haskell-sdk.cabal
@@ -1,6 +1,6 @@
 cabal-version:   3.0
 name:            solana-haskell-sdk
-version:         1.2.0.0
+version:         1.3.0.0
 synopsis:        Solana SDK: transaction building, signing, program clients, and JSON-RPC.
 homepage:        https://github.com/mariusgeorgescu/solana-haskell-sdk
 bug-reports:     https://github.com/mariusgeorgescu/solana-haskell-sdk/issues
@@ -141,6 +141,31 @@
   -- Base language which the package is written in.
   default-language: GHC2021
 
+-- The README's SPL-token example, compiled so the documented flow cannot
+-- silently break (Test.Readme keeps the README text identical to app/).
+executable example-spl-transfer
+  import:           warnings
+  main-is:          SplTransfer.hs
+  build-depends:
+    , base                ^>=4.18.0.0
+    , solana-haskell-sdk
+    , web3-provider       ^>=1.1
+
+  hs-source-dirs:   app
+  default-language: GHC2021
+
+-- The README's priority-fee example, compiled for the same reason.
+executable example-priority-fee
+  import:           warnings
+  main-is:          PriorityFee.hs
+  build-depends:
+    , base                ^>=4.18.0.0
+    , solana-haskell-sdk
+    , web3-provider       ^>=1.1
+
+  hs-source-dirs:   app
+  default-language: GHC2021
+
 test-suite solana-haskell-sdk-test
   import:           warnings
   default-language: GHC2021
@@ -168,7 +193,10 @@
     Test.NativePrograms.Vote
     Test.RPC.Chain
     Test.RPC.Parsers
+    Test.RPC.Types
     Test.RPC.WebSocket
+    Test.Readme
+    Test.SolanaWeb3
     Test.SplPrograms.AssociatedTokenAccount
     Test.SplPrograms.Memo
     Test.SplPrograms.Token
@@ -193,6 +221,7 @@
   main-is:          Main.hs
   other-modules:
     Test.Integration.Alt
+    Test.Integration.Block
     Test.Integration.Nonce
     Test.Integration.PriorityFee
     Test.Integration.Setup
diff --git a/src/Network/Solana/Core/Account.hs b/src/Network/Solana/Core/Account.hs
--- a/src/Network/Solana/Core/Account.hs
+++ b/src/Network/Solana/Core/Account.hs
@@ -12,7 +12,6 @@
 import Data.Text qualified as T
 import Data.Vector qualified as V
 import Data.Word (Word64)
-import GHC.Base (Alternative (..))
 import GHC.Generics (Generic)
 import Network.Solana.Constants
 import Network.Solana.Core.Crypto
@@ -99,22 +98,39 @@
 
 ------------------------------------------------------------------------------------------------
 
--- | A byte array that stores arbitrary data for an account.
+-- | An account's @data@ field as the node returns it: the raw bytes for the
+-- @base58@ / @base64@ encodings, or the node's own program-parsed view for
+-- @jsonParsed@.
+--
+-- On the wire, binary @data@ is either a bare Base58 string (the node's
+-- default @binary@ encoding, only offered for accounts of at most 128 bytes)
+-- or a @[data, encoding]@ pair; 'toJSON' emits the bare Base58 form. With
+-- @jsonParsed@ the node only parses accounts whose owner program it has a
+-- parser for and falls back to the @base64@ pair otherwise, so a
+-- @jsonParsed@ request can still yield 'AccountDataBinary'.
 data AccountData
   = AccountDataBinary
       { accData :: S.ByteString
       }
-  | AccountDataJSON {accDataObj :: String}
+  | AccountDataJSON
+      { -- | The node parser that produced 'accDataParsed' (e.g. @"nonce"@, @"spl-token"@, @"sysvar"@).
+        accDataProgram :: String,
+        -- | The program-specific parsed state, as the node returned it.
+        accDataParsed :: Value,
+        -- | The account's data length in bytes.
+        accDataSpace :: Word64
+      }
   deriving (Eq, Generic)
 
 instance Show AccountData where
   show :: AccountData -> String
   show (AccountDataBinary bs) = toBase58String bs
-  show (AccountDataJSON o) = show o
+  show (AccountDataJSON prog parsed _) = prog <> ": " <> show parsed
 
 instance ToJSON AccountData where
   toJSON :: AccountData -> Value
-  toJSON ac = toJSON (show ac)
+  toJSON (AccountDataBinary bs) = toJSON (toBase58String bs)
+  toJSON (AccountDataJSON prog parsed space) = object ["program" .= prog, "parsed" .= parsed, "space" .= space]
 
 instance FromJSON AccountData where
   parseJSON :: Value -> Parser AccountData
@@ -141,9 +157,16 @@
                   else case arr V.! 1 of
                     "base58" -> base58StringParser $ arr V.! 0
                     "base64" -> base64StringParser $ arr V.! 0
-                    "json" -> withText "AccountDataJSON" (return . AccountDataJSON . T.unpack) $ arr V.! 0
-                    "jsonParsed" -> withText "AccountDataJSON" (return . AccountDataJSON . T.unpack) $ arr V.! 0
                     other -> fail ("AccountData: unsupported encoding: " <> show other)
             )
             v
-     in base64StringParser v <|> encodedParser
+
+        parsedParser =
+          withObject
+            "AccountDataJSON"
+            (\o -> AccountDataJSON <$> o .: "program" <*> o .: "parsed" <*> o .: "space")
+     in case v of
+          String _ -> base58StringParser v
+          Array _ -> encodedParser
+          Object _ -> parsedParser v
+          _ -> typeMismatch "AccountData" v
diff --git a/src/Network/Solana/Core/Crypto.hs b/src/Network/Solana/Core/Crypto.hs
--- a/src/Network/Solana/Core/Crypto.hs
+++ b/src/Network/Solana/Core/Crypto.hs
@@ -33,6 +33,7 @@
     readSigningKeyFromFile,
     mkPublicKeyFromString,
     mkPrivateKeyFromString,
+    mkPrivateKeyFromBytes,
   )
 where
 
@@ -46,12 +47,9 @@
 import Data.ByteString qualified as BS
 import Data.ByteString.Base58
 import Data.ByteString.Base64 (decodeBase64Lenient, encodeBase64')
-import Data.ByteString.Char8 qualified as BS8
 import Data.Either.Extra (maybeToEither)
 import Data.String (IsString, fromString)
 import Data.Text qualified as Text
-import GHC.Generics (Generic)
-import Text.Read (readMaybe)
 
 -- | Encode a byte string as Base58 text (Bitcoin alphabet), the encoding
 -- Solana uses for addresses, signatures and hashes.
@@ -87,7 +85,7 @@
 -- | A 64-byte detached Ed25519 signature. 'Show' and the JSON instances use
 -- the Base58 rendering.
 newtype SolanaSignature = SolanaSignature Ed25519.Signature
-  deriving (Eq, Ord, Generic)
+  deriving (Eq, Ord)
 
 instance Show SolanaSignature where
   show :: SolanaSignature -> String
@@ -118,7 +116,7 @@
 -- 'IsString' instance is partial (see 'unsafeSolanaPublicKey').
 newtype SolanaPublicKey
   = SolanaPublicKey Ed25519.PublicKey
-  deriving (Eq, Ord, Generic)
+  deriving (Eq, Ord)
 
 instance Show SolanaPublicKey where
   show :: SolanaPublicKey -> String
@@ -159,7 +157,7 @@
 -- 'Show' renders it in Base58 — avoid logging values of this type.
 newtype SolanaPrivateKey
   = SolanaPrivateKey Ed25519.SecretKey
-  deriving (Eq, Ord, Generic)
+  deriving (Eq, Ord)
 
 instance Show SolanaPrivateKey where
   show :: SolanaPrivateKey -> String
@@ -196,35 +194,51 @@
 mkPublicKeyFromString = mkKeyFromString 32 (SolanaPublicKey . Ed25519.PublicKey)
 
 -- | Parse Base58 text into a 'SolanaPrivateKey'. 'Left' if the input is not
--- Base58 or has the wrong length.
+-- Base58 or fails the checks of 'mkPrivateKeyFromBytes' (64 bytes whose
+-- public-key half is derived from the seed).
 mkPrivateKeyFromString :: String -> Either String SolanaPrivateKey
-mkPrivateKeyFromString = mkKeyFromString 64 (SolanaPrivateKey . Ed25519.SecretKey)
+mkPrivateKeyFromString str = maybeToEither "Not base58" (fromBase58String str) >>= mkPrivateKeyFromBytes
 
+-- | Build a 'SolanaPrivateKey' from the raw 64 bytes of a NaCl secret key
+-- (32-byte seed followed by the 32-byte public key). 'Left' unless the input
+-- is exactly 64 bytes and its public-key half is the one derived from the
+-- seed — the checks @solana-sdk@'s @Keypair::from_bytes@ performs.
+mkPrivateKeyFromBytes :: BS.ByteString -> Either String SolanaPrivateKey
+mkPrivateKeyFromBytes bs
+  | BS.length bs /= 64 = Left ("Invalid private key length: expected 64 bytes, got " <> show (BS.length bs))
+  | otherwise = case createSolanaKeypairFromSeed (BS.take 32 bs) of
+      Just (_, sk) | getSolanaPrivateKeyRaw sk == bs -> Right sk
+      _ -> Left "Private key public-key half does not match the key derived from its seed"
+
 unsafeKeyFromString :: forall f. Int -> (BS.ByteString -> f) -> String -> f
 unsafeKeyFromString n cstr str = either error id $ mkKeyFromString n cstr str
 
-unsafeKeyFromWords :: forall f. (BS.ByteString -> f) -> [Word8] -> f
-unsafeKeyFromWords cstr ws = cstr (BS.pack ws)
+unsafeKeyFromWords :: forall f. Int -> (BS.ByteString -> f) -> [Word8] -> f
+unsafeKeyFromWords n cstr ws
+  | length ws == n = cstr (BS.pack ws)
+  | otherwise = error ("Invalid key length: expected " <> show n <> " bytes, got " <> show (length ws))
 
 -- | Partial version of 'mkPublicKeyFromString': calls 'error' on invalid
 -- input. Prefer the total variant outside of literals and tests.
 unsafeSolanaPublicKey :: String -> SolanaPublicKey
 unsafeSolanaPublicKey = unsafeKeyFromString 32 (SolanaPublicKey . Ed25519.PublicKey)
 
--- | Build a 'SolanaPublicKey' directly from raw bytes. No length check is
--- performed — the caller must supply exactly 32 bytes.
+-- | Build a 'SolanaPublicKey' directly from raw bytes. Calls 'error' unless
+-- exactly 32 bytes are supplied.
 unsafeSolanaPublicKeyRaw :: [Word8] -> SolanaPublicKey
-unsafeSolanaPublicKeyRaw = unsafeKeyFromWords (SolanaPublicKey . Ed25519.PublicKey)
+unsafeSolanaPublicKeyRaw = unsafeKeyFromWords 32 (SolanaPublicKey . Ed25519.PublicKey)
 
 -- | Partial version of 'mkPrivateKeyFromString': calls 'error' on invalid
 -- input.
 unsafeSolanaPrivateKey :: String -> SolanaPrivateKey
-unsafeSolanaPrivateKey = unsafeKeyFromString 64 (SolanaPrivateKey . Ed25519.SecretKey)
+unsafeSolanaPrivateKey = either error id . mkPrivateKeyFromString
 
--- | Build a 'SolanaPrivateKey' directly from raw bytes (e.g. the 64 numbers
--- in a @solana-keygen@ keypair file). No length check is performed.
+-- | Build a 'SolanaPrivateKey' directly from the raw 64 bytes of a NaCl
+-- secret key. Calls 'error' on any other length; the public-key half is not
+-- checked — prefer 'mkPrivateKeyFromBytes' (or 'readSigningKeyFromFile' for
+-- @solana-keygen@ files).
 unsafeSolanaPrivateKeyRaw :: [Word8] -> SolanaPrivateKey
-unsafeSolanaPrivateKeyRaw = unsafeKeyFromWords (SolanaPrivateKey . Ed25519.SecretKey)
+unsafeSolanaPrivateKeyRaw = unsafeKeyFromWords 64 (SolanaPrivateKey . Ed25519.SecretKey)
 
 -- | The raw 32 bytes of a public key.
 getSolanaPublicKeyRaw :: SolanaPublicKey -> BS.ByteString
@@ -274,12 +288,17 @@
 ----
 ----
 
--- | Read a private key from a @solana-keygen@-style keypair file containing
--- a list of byte values (e.g. @[1,2,...]@). Throws an 'IOError' if the file
--- cannot be read, or if its contents cannot be parsed as a @[Word8]@ list.
+-- | Read a private key from a @solana-keygen@-style keypair file: a JSON
+-- array of the 64 byte values of the secret key (e.g. @[1,2,...]@). Throws
+-- an 'IOError' if the file cannot be read, is not an array of exactly 64
+-- integers in @0..255@, or fails the checks of 'mkPrivateKeyFromBytes'.
 readSigningKeyFromFile :: FilePath -> IO SolanaPrivateKey
 readSigningKeyFromFile path = do
-  contents <- BS8.readFile path
-  case readMaybe (BS8.unpack contents) of
-    Just word8List -> return $ unsafeSolanaPrivateKeyRaw (word8List :: [Word8])
-    Nothing -> fail ("readSigningKeyFromFile: could not parse " <> path <> " as a list of bytes (e.g. \"[1,2,...]\")")
+  contents <- BS.readFile path
+  -- The JSON parser's own error would quote the unparsed remainder of the
+  -- file, i.e. secret bytes, so decode failures get a fixed message.
+  case eitherDecodeStrict contents of
+    Left _ -> failWith "not a JSON array of 64 integers in 0..255"
+    Right ws -> either failWith return (mkPrivateKeyFromBytes (BS.pack ws))
+  where
+    failWith err = fail ("readSigningKeyFromFile: " <> path <> ": " <> err)
diff --git a/src/Network/Solana/Core/Instruction.hs b/src/Network/Solana/Core/Instruction.hs
--- a/src/Network/Solana/Core/Instruction.hs
+++ b/src/Network/Solana/Core/Instruction.hs
@@ -1,6 +1,12 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
 
+-- | Instructions -- a program id, the 'AccountMeta's it touches and its input
+-- bytes -- and their compilation into the message wire format:
+-- 'compileInstruction' resolves each account (and the program id) to an
+-- index into a message's ordered account list, failing with
+-- 'CompileException' when a key is absent or its index does not fit in a
+-- byte.
 module Network.Solana.Core.Instruction
   ( Instruction,
     mkInstruction,
@@ -148,28 +154,45 @@
 
 -- | Replace each pubkey referenced by an instruction with its index into
 -- the given account-key table. 'Left' when a key is not present in the
--- table.
+-- table, or sits at position 256 or beyond -- a compiled index is a single
+-- byte, so such a key is rejected rather than silently wrapped into the
+-- wrong index (mirroring the Rust SDK's @CompileError::AccountIndexOverflow@).
 compileInstruction :: [SolanaPublicKey] -> Instruction -> Either CompileException CompiledInstruction
 compileInstruction keys instruction = do
   programIdIndex <- keyToIndex (iProgramId instruction) keys
   accIndices <- mapM ((`keyToIndex` keys) . accountPubKey) (iAccounts instruction)
   return $
     CompiledInstruction
-      { ciProgramIdIndex = fromIntegral programIdIndex,
-        ciAccounts = mkCompact (fromIntegral <$> accIndices),
+      { ciProgramIdIndex = programIdIndex,
+        ciAccounts = mkCompact accIndices,
         ciData = mkCompact . S.unpack $ instrData (iData instruction)
       }
 
-keyToIndex :: SolanaPublicKey -> [SolanaPublicKey] -> Either CompileException Int
-keyToIndex k keys = maybeToRight (MissingIndex $ show k) $ k `elemIndex` keys
+-- | Position of a key in the account table, narrowed to the byte the wire
+-- format requires; 'Left' if the key is absent or its position does not
+-- fit in a byte.
+keyToIndex :: SolanaPublicKey -> [SolanaPublicKey] -> Either CompileException Word8
+keyToIndex k keys = do
+  i <- maybeToRight (MissingIndex $ show k) $ k `elemIndex` keys
+  if i <= fromIntegral (maxBound :: Word8)
+    then Right (fromIntegral i)
+    else
+      Left
+        ( MissingIndex
+            ( "account index overflow: " <> show k <> " sits at position " <> show i
+                <> " of the account table, past the 256 addressable by a byte"
+            )
+        )
 
 ------------------------------------------------------------------------------------------------
 
 -- *** CompileException
 
 ------------------------------------------------------------------------------------------------
--- | Compilation failure: an instruction references an account key that is
--- missing from the message's account table.
+-- | Compilation failure, carrying a message: an instruction references an
+-- account key that is missing from the message's account table, an account
+-- or lookup-table index does not fit in a byte, or a signing key does not
+-- match the message's required signers.
 newtype CompileException = MissingIndex String
   deriving (Show)
 
diff --git a/src/Network/Solana/Core/Message.hs b/src/Network/Solana/Core/Message.hs
--- a/src/Network/Solana/Core/Message.hs
+++ b/src/Network/Solana/Core/Message.hs
@@ -18,6 +18,8 @@
     newMessage,
     newMessageToBase64String,
     mkNewMessage,
+    mkNewMessageWithPayer,
+    orderSigningKeys,
   )
 where
 
@@ -56,6 +58,11 @@
 -- account keys. If you would rather name the fee payer explicitly and not
 -- worry about signer order, consider 'newTransactionIntentWithPayer',
 -- which orders signatures automatically.
+--
+-- If no instruction marks a signer writable (a memo-only or SPL
+-- authority-only instruction list), the message compiled here has no valid
+-- fee payer and the node rejects it at sanitize time; use
+-- 'newTransactionIntentWithPayer' for such transactions.
 newTransactionIntent :: [SolanaPrivateKey] -> [Instruction] -> SignedTransactionIntent
 newTransactionIntent signers instructions blockhash = do
   msg <- newMessage blockhash instructions -- make the binary message
@@ -76,21 +83,30 @@
 newTransactionIntentWithPayer payer signingKeys instructions blockhash = do
   let msg = mkNewMessageWithPayer payer blockhash instructions
   msgBytes <- compileMessageToBinary msg
-  let requiredSigners = take (fromIntegral (numRequiredSignatures (mHeader msg))) (mAccountKeys msg)
-      keyedByPubkey = [(toSolanaPublicKey k, k) | k <- signingKeys]
-  orderedKeys <- mapM (findSigningKey keyedByPubkey) requiredSigners
-  mapM_ (checkKeyIsRequired requiredSigners . fst) keyedByPubkey
+  orderedKeys <- orderSigningKeys msg signingKeys
   let signatures = S.toStrict . Data.Binary.encode $ mkCompact $ flip dsign msgBytes <$> orderedKeys
   return $ toBase64String $ S.append signatures msgBytes
+
+-- | Orders the given private keys to match the required signers of the given
+-- message (its first @numRequiredSignatures@ account keys, fee payer first).
+-- 'Left' if a required signer has no corresponding key, or if a given key
+-- corresponds to no required signer. Duplicate keys for the same signer are
+-- tolerated: the first match signs, mirroring the Rust SDK's @try_sign@.
+orderSigningKeys :: Message -> [SolanaPrivateKey] -> Either CompileException [SolanaPrivateKey]
+orderSigningKeys msg signingKeys = do
+  orderedKeys <- mapM findSigningKey requiredSigners
+  mapM_ (checkKeyIsRequired . fst) keyedByPubkey
+  pure orderedKeys
   where
-    findSigningKey keyedByPubkey pk =
+    requiredSigners = take (fromIntegral (numRequiredSignatures (mHeader msg))) (mAccountKeys msg)
+    keyedByPubkey = [(toSolanaPublicKey k, k) | k <- signingKeys]
+    findSigningKey pk =
       case lookup pk keyedByPubkey of
         Just k -> Right k
         Nothing -> Left (MissingIndex ("missing signer for " <> show pk))
-    checkKeyIsRequired requiredSigners pk =
-      if pk `elem` requiredSigners
-        then Right ()
-        else Left (MissingIndex ("unused signing key " <> show pk))
+    checkKeyIsRequired pk
+      | pk `elem` requiredSigners = Right ()
+      | otherwise = Left (MissingIndex ("unused signing key " <> show pk))
 
 -- | Builds and signs a durable-nonce transaction: prepends
 -- @SystemProgram.advanceNonceAccount nonceAccount nonceAuthority@ ahead of
@@ -168,7 +184,7 @@
 -- | Like 'mkNewMessage', but with an explicitly named fee payer. The payer
 -- is seeded as a writable signer before the instructions' account metas are
 -- folded in, so it ends up in the message (and pinned first by
--- 'canonicalizeAccountOrder') even if no instruction references it —
+-- @canonicalizeAccountOrder@) even if no instruction references it —
 -- enabling sponsored-fee transactions.
 mkNewMessageWithPayer :: SolanaPublicKey -> BlockHash -> [Instruction] -> Message
 mkNewMessageWithPayer payer bh =
diff --git a/src/Network/Solana/Core/VersionedMessage.hs b/src/Network/Solana/Core/VersionedMessage.hs
--- a/src/Network/Solana/Core/VersionedMessage.hs
+++ b/src/Network/Solana/Core/VersionedMessage.hs
@@ -7,7 +7,9 @@
   ( AddressLookupTableAccount (..),
     MessageAddressTableLookup (..),
     compileV0Message,
+    compileV0MessageWithPayer,
     newV0TransactionIntent,
+    newV0TransactionIntentWithPayer,
   )
 where
 
@@ -94,6 +96,9 @@
 -- cannot be represented in the byte-sized lookup index the wire format
 -- requires, so it is rejected rather than silently truncated (wrapped) into
 -- the wrong index, mirroring Rust's @AddressLookupTableIndexOverflow@.
+-- Compilation also fails when the static and table-loaded keys together
+-- exceed 256, since instruction account indices are single bytes (the
+-- on-chain v0 sanitize rule; see 'compileInstruction').
 --
 -- __A trap this module can't protect you from:__ an address only just added
 -- to a lookup table by an @ExtendLookupTable@ instruction that landed in
@@ -114,12 +119,27 @@
 -- 'Network.Solana.SolanaWeb3.getLookupTable' drops that field and returns
 -- only 'AddressLookupTableAccount', so it can't be used for this check.
 compileV0Message :: BlockHash -> [Instruction] -> [AddressLookupTableAccount] -> Either CompileException BS.ByteString
-compileV0Message bh instructions tables = do
-  let legacy = mkNewMessage bh instructions
-      header = mHeader legacy
+compileV0Message bh instructions = compileV0FromLegacy (mkNewMessage bh instructions)
+
+-- | Like 'compileV0Message', but with an explicitly named fee payer, seeded
+-- as a writable signer and pinned to account 0 via
+-- 'Network.Solana.Core.Message.mkNewMessageWithPayer' -- which is what the
+-- Rust SDK's @v0::Message::try_compile(payer, ..)@ always does. Required
+-- when no instruction marks a signer writable (a memo-only or SPL
+-- authority-only instruction list) and for sponsored fees.
+compileV0MessageWithPayer ::
+  SolanaPublicKey -> BlockHash -> [Instruction] -> [AddressLookupTableAccount] -> Either CompileException BS.ByteString
+compileV0MessageWithPayer payer bh instructions = compileV0FromLegacy (mkNewMessageWithPayer payer bh instructions)
+
+-- | Move eligible keys of an assembled legacy message into the given lookup
+-- tables and serialize the v0 message (shared body of 'compileV0Message'
+-- and 'compileV0MessageWithPayer').
+compileV0FromLegacy :: Message -> [AddressLookupTableAccount] -> Either CompileException BS.ByteString
+compileV0FromLegacy legacy tables = do
+  let header = mHeader legacy
       keys = mAccountKeys legacy
       (rws, ros, rwus, rous) = splitAccountsByPurpose header keys
-      programIds = iProgramId <$> instructions
+      programIds = iProgramId <$> mInstructions legacy
       (rwusRemaining, rousRemaining, tableLoads) = drainTables programIds rwus rous tables
       statics = rws <> ros <> rwusRemaining <> rousRemaining
       newHeader = header {numReadonlyUnsignedAccounts = fromIntegral (length rousRemaining)}
@@ -147,7 +167,8 @@
 -- followed by the message bytes). Mirrors 'Network.Solana.Core.Message.newTransactionIntent'.
 -- The private keys passed here must be ordered to match the resulting account
 -- order (fee payer first), otherwise the produced signatures will not correspond
--- to the right account keys.
+-- to the right account keys. If you would rather name the fee payer explicitly
+-- and not worry about signer order, use 'newV0TransactionIntentWithPayer'.
 --
 -- If any given table was extended very recently, see the note on
 -- 'compileV0Message' about the resulting transaction's activation window:
@@ -158,6 +179,21 @@
 newV0TransactionIntent signers instructions tables bh = do
   msg <- compileV0Message bh instructions tables
   let signatures = BL.toStrict . encode $ mkCompact $ flip dsign msg <$> signers
+  return $ toBase64String $ BS.append signatures msg
+
+-- | Like 'newV0TransactionIntent', but with an explicitly named fee payer
+-- (see 'compileV0MessageWithPayer'); the given private keys may be listed
+-- in any order -- they are matched against the message's required signers
+-- and placed in message order automatically, with the same 'Left' cases as
+-- 'Network.Solana.Core.Message.newTransactionIntentWithPayer'.
+newV0TransactionIntentWithPayer ::
+  SolanaPublicKey -> [SolanaPrivateKey] -> [Instruction] -> [AddressLookupTableAccount] -> BlockHash ->
+  Either CompileException String
+newV0TransactionIntentWithPayer payer signingKeys instructions tables bh = do
+  let legacy = mkNewMessageWithPayer payer bh instructions
+  msg <- compileV0FromLegacy legacy tables
+  orderedKeys <- orderSigningKeys legacy signingKeys
+  let signatures = BL.toStrict . encode $ mkCompact $ flip dsign msg <$> orderedKeys
   return $ toBase64String $ BS.append signatures msg
 
 ------------------------------------------------------------------------------------------------
diff --git a/src/Network/Solana/Metaplex/TokenMetadata.hs b/src/Network/Solana/Metaplex/TokenMetadata.hs
--- a/src/Network/Solana/Metaplex/TokenMetadata.hs
+++ b/src/Network/Solana/Metaplex/TokenMetadata.hs
@@ -353,7 +353,8 @@
 -- 2. `[SIGNER]` Update authority
 -- 3. `[SIGNER]` Mint authority
 -- 4. `[WRITE, SIGNER]` Payer
--- 5. `[]` Metadata account (derived)
+-- 5. `[WRITE]` Metadata account (derived; the program upgrades its @token_standard@ to
+--    @NonFungible@ only if it is writable)
 -- 6. `[]` Token program
 -- 7. `[]` System program
 -- 8. `[]` Rent sysvar
@@ -366,7 +367,7 @@
       AccountMeta {accountPubKey = updateAuthority, isSigner = True, isWritable = False},
       AccountMeta {accountPubKey = mintAuthority, isSigner = True, isWritable = False},
       AccountMeta {accountPubKey = payer, isSigner = True, isWritable = True},
-      AccountMeta {accountPubKey = metadata, isSigner = False, isWritable = False},
+      AccountMeta {accountPubKey = metadata, isSigner = False, isWritable = True},
       AccountMeta {accountPubKey = Token.tokenProgramId, isSigner = False, isWritable = False},
       AccountMeta {accountPubKey = SystemProgram.systemProgramId, isSigner = False, isWritable = False},
       AccountMeta {accountPubKey = Sysvar.rent, isSigner = False, isWritable = False}
diff --git a/src/Network/Solana/NativePrograms/ComputeBudget.hs b/src/Network/Solana/NativePrograms/ComputeBudget.hs
--- a/src/Network/Solana/NativePrograms/ComputeBudget.hs
+++ b/src/Network/Solana/NativePrograms/ComputeBudget.hs
@@ -1,5 +1,9 @@
 {-# LANGUAGE OverloadedStrings #-}
 
+-- | Client for the Compute Budget program: instructions setting a
+-- transaction's compute-unit limit, compute-unit price (priority fee), heap
+-- size and loaded-accounts data size limit. Instruction data is
+-- byte-verified against the Rust SDK.
 module Network.Solana.NativePrograms.ComputeBudget where
 
 import Data.Binary
diff --git a/src/Network/Solana/NativePrograms/SystemProgram.hs b/src/Network/Solana/NativePrograms/SystemProgram.hs
--- a/src/Network/Solana/NativePrograms/SystemProgram.hs
+++ b/src/Network/Solana/NativePrograms/SystemProgram.hs
@@ -1,5 +1,9 @@
 {-# LANGUAGE OverloadedStrings #-}
 
+-- | Client for the System program: account creation and allocation (plain
+-- and seed-derived), program assignment, lamport transfers and durable-nonce
+-- account management, plus 'decodeNonceAccount' for nonce account state.
+-- Instruction data is byte-verified against the Rust SDK.
 module Network.Solana.NativePrograms.SystemProgram where
 
 import Data.Binary
diff --git a/src/Network/Solana/RPC/HTTP/Block.hs b/src/Network/Solana/RPC/HTTP/Block.hs
--- a/src/Network/Solana/RPC/HTTP/Block.hs
+++ b/src/Network/Solana/RPC/HTTP/Block.hs
@@ -32,7 +32,14 @@
 
 -- | Returns identity and transaction information about a confirmed block in
 -- the ledger, using the given configuration.
--- Returns 'Nothing' if the slot has been skipped or pruned from the ledger.
+--
+-- A slot that holds no block is answered by the node with a JSON-RPC error,
+-- not with @null@: @-32007@ (slot skipped), @-32001@ (pruned from the ledger)
+-- or @-32004@ (not yet produced or rooted). The transport raises such errors
+-- as a @JsonRpcException@ (@CallException@) that @runWeb3'@ does not catch,
+-- so wrap the call in 'Control.Exception.try' to handle them. 'Nothing' is
+-- returned only when the node itself answers @null@, which Agave does solely
+-- for a rooted slot missing from its blockstore without being flagged skipped.
 getBlock' :: (JsonRpc m) => Slot -> ConfigurationObject -> m (Maybe BlockInfo)
 getBlock' = do
   remote "getBlock"
@@ -45,7 +52,8 @@
 -- transactions are returned without their address-lookup-table data, so
 -- instruction account indices may reference addresses not present in the
 -- parsed account keys.
--- Returns 'Nothing' if the slot has been skipped or pruned from the ledger.
+-- A slot holding no block is a JSON-RPC error rather than 'Nothing'; see
+-- 'getBlock''.
 getBlock :: (JsonRpc m) => Slot -> m (Maybe BlockInfo)
 getBlock slot = getBlock' slot (defaultConfigObject {encoding = Just "json", maxSupportedTransactionVersion = Just 0})
 {-# INLINE getBlock #-}
@@ -209,7 +217,8 @@
 
 -- | Returns the estimated production time of a block (as Unix timestamp).
 -- This is based on stake-weighted votes and validator-reported timestamps.
--- Returns 'Nothing' if the timestamp is not available for the given slot.
+-- Returns 'Nothing' if the block exists but carries no timestamp; a slot
+-- holding no block is a JSON-RPC error, as for 'getBlock''.
 getBlockTime :: (JsonRpc m) => Slot -> m (Maybe Int)
 getBlockTime = do
   remote "getBlockTime"
diff --git a/src/Network/Solana/RPC/HTTP/Chain.hs b/src/Network/Solana/RPC/HTTP/Chain.hs
--- a/src/Network/Solana/RPC/HTTP/Chain.hs
+++ b/src/Network/Solana/RPC/HTTP/Chain.hs
@@ -142,8 +142,9 @@
     numSlots :: Word64,
     -- | Duration of the sampling window, in seconds.
     samplePeriodSecs :: Word16,
-    -- | Number of non-vote transactions during the sample.
-    numNonVoteTransactions :: Word64
+    -- | Number of non-vote transactions during the sample; 'Nothing' (@null@
+    -- on the wire) for older samples that do not record it.
+    numNonVoteTransactions :: Maybe Word64
   }
   deriving (Generic, Show, FromJSON)
 
@@ -208,8 +209,9 @@
 data SolanaVersion = SolanaVersion
   { -- | Software version of 'solana-core'.
     solana_core :: String,
-    -- | Unique identifier of the software's feature set.
-    feature_set :: Word32
+    -- | Unique identifier of the software's feature set; 'Nothing' if the
+    -- node does not report one.
+    feature_set :: Maybe Word32
   }
   deriving (Generic, Show, Eq)
 
@@ -218,4 +220,4 @@
   parseJSON = withObject "SolanaVersion" $ \v ->
     SolanaVersion
       <$> v .: "solana-core"
-      <*> v .: "feature-set"
+      <*> v .:? "feature-set"
diff --git a/src/Network/Solana/RPC/HTTP/Types.hs b/src/Network/Solana/RPC/HTTP/Types.hs
--- a/src/Network/Solana/RPC/HTTP/Types.hs
+++ b/src/Network/Solana/RPC/HTTP/Types.hs
@@ -30,8 +30,9 @@
 --
 -- Includes API version and the slot at which the response is valid.
 data Context = Context
-  { -- | API version string returned by the cluster (e.g. @"1.17.0"@).
-    apiVersion :: Text,
+  { -- | API version string reported by the node (e.g. @"2.1.16"@); 'Nothing'
+    -- when the node omits it, as older nodes and some RPC proxies do.
+    apiVersion :: Maybe Text,
     -- | The slot at which the data in the response is valid.
     contextSlot :: Slot
   }
@@ -41,7 +42,7 @@
   parseJSON :: Value -> Parser Context
   parseJSON = withObject "Context" $ \v ->
     Context
-      <$> v .: "apiVersion"
+      <$> v .:? "apiVersion"
       <*> v .: "slot"
 
 -- | Generic wrapper for Solana RPC responses that include a context and a value.
@@ -77,7 +78,9 @@
 data ConfigurationObject = ConfigurationObject
   { -- | Optional commitment level (e.g. @"finalized"@, @"confirmed"@).
     commitment :: Maybe String,
-    -- | Desired encoding for returned data (e.g. @"base58"@, @"base64"@).
+    -- | Desired encoding for returned data (e.g. @"base58"@, @"base64"@,
+    -- @"jsonParsed"@). Account data returned as @"base64+zstd"@ is not
+    -- decoded by 'Network.Solana.Core.Account.AccountData' and is rejected.
     encoding :: Maybe String,
     -- | Optional partial data slice configuration.
     dataSlice :: Maybe Object,
diff --git a/src/Network/Solana/RPC/WebSocket.hs b/src/Network/Solana/RPC/WebSocket.hs
--- a/src/Network/Solana/RPC/WebSocket.hs
+++ b/src/Network/Solana/RPC/WebSocket.hs
@@ -196,9 +196,9 @@
 -- | Parses one PubSub frame.
 --
 -- Note that PubSub notifications carry a @context@ object holding only a
--- @slot@ -- unlike the HTTP RPC responses modelled by
--- 'Network.Solana.RPC.HTTP.Types.Context', they omit @apiVersion@ -- so they
--- are parsed here rather than through @RPCResponse@.
+-- @slot@ (no @apiVersion@, unlike the HTTP RPC responses modelled by
+-- 'Network.Solana.RPC.HTTP.Types.Context'), so they are parsed here rather
+-- than through @RPCResponse@.
 parseWsMessage :: BS.ByteString -> Either String WsMessage
 parseWsMessage raw = eitherDecodeStrict' raw >>= parseEither wsMessageParser
 
@@ -244,7 +244,9 @@
   case value of
     String "receivedSignature" -> pure (SignatureNotification slot Nothing True)
     _ -> flip (withObject "signature notification value") value $ \v -> do
-      err <- v .:? "err"
+      -- The node always sends @err@ (null on success); a value without it
+      -- is malformed, not a success.
+      err <- v .: "err"
       pure (SignatureNotification slot err False)
 
 accountNotificationParser :: Value -> Parser AccountNotification
diff --git a/src/Network/Solana/SolanaWeb3.hs b/src/Network/Solana/SolanaWeb3.hs
--- a/src/Network/Solana/SolanaWeb3.hs
+++ b/src/Network/Solana/SolanaWeb3.hs
@@ -13,9 +13,12 @@
 -- 'getLookupTable', 'getStakeAccount', 'getNonceAccount',
 -- 'getMetadataAccount') that fetch an account over RPC and decode its state
 -- with the corresponding on-chain-state decoder, so callers don't have to
--- extract and decode 'Network.Solana.Core.Account.AccountData' by hand; like
--- every other helper in this module, they require a reachable RPC node and
--- are compile-verified only.
+-- extract and decode 'Network.Solana.Core.Account.AccountData' by hand. Like
+-- every other helper in this module, they require a reachable RPC node, so
+-- the unit suite only compiles them; live coverage comes from the opt-in
+-- local-validator integration suite (@cabal test integration-tests
+-- --flags=integration@, see the README), which exercises most but not all of
+-- them.
 module Network.Solana.SolanaWeb3 where
 
 import Control.Concurrent (threadDelay)
@@ -27,7 +30,7 @@
 import Network.Solana.Core.Account (AccountData (..), AccountInfo (dataField))
 import Network.Solana.Core.Crypto
 import Network.Solana.Core.Instruction
-import Network.Solana.Core.Message (newDurableNonceTransactionIntentWithPayer, newTransactionIntent)
+import Network.Solana.Core.Message (newDurableNonceTransactionIntentWithPayer, newTransactionIntentWithPayer)
 import Network.Solana.Core.VersionedMessage qualified as VM
 import Network.Solana.Metaplex.TokenMetadata qualified as TM
 import Network.Solana.NativePrograms.AddressLookupTable qualified as ALT
@@ -37,7 +40,13 @@
 import Network.Solana.RPC.HTTP.Block (getTheLatestBlockhash)
 import Network.Solana.RPC.HTTP.Chain (PrioritizationFee (prioritizationFee), getRecentPrioritizationFees, percentilePriorityFee)
 import Network.Solana.RPC.HTTP.Transaction
-import Network.Solana.RPC.HTTP.Types (ConfigurationObject, cfgJustEncodingBase64, commitment, value)
+import Network.Solana.RPC.HTTP.Types
+  ( ConfigurationObject,
+    cfgJustEncodingBase64,
+    commitment,
+    preflightCommitment,
+    value,
+  )
 import Network.Solana.SplPrograms.Token qualified as Tok
 import Network.Web3 hiding (AccountData, value)
 
@@ -45,16 +54,27 @@
 -- instructions, returning its signature.
 --
 -- Fetches the latest blockhash from the cluster, compiles the instructions
--- into a message, signs it with the given keys (the first key is the fee
--- payer), and broadcasts the result with 'sendTransaction'.
+-- with 'newTransactionIntentWithPayer' naming the first key as the fee
+-- payer (forced into account 0 as a writable signer, even if no instruction
+-- marks it writable -- e.g. a memo-only or SPL authority-only transaction
+-- -- or references it at all), signs with the given keys (any order;
+-- signatures are placed in message order automatically), and broadcasts
+-- the result with 'sendTransaction'.
 --
--- Throws a 'CompileException' if an instruction references an account key
--- that cannot be resolved in the compiled message.
+-- Throws @'userError' "newTransaction: no signers given"@ if the key list
+-- is empty, and a 'CompileException' if an instruction references an
+-- account key that cannot be resolved in the compiled message, if a
+-- required signer has no corresponding key, or if a given key signs
+-- nothing.
 newTransaction :: [SolanaPrivateKey] -> [Instruction] -> Web3 SolanaSignature
-newTransaction signers instructions = do
-  let newTxInt = newTransactionIntent signers instructions
+newTransaction [] _ = liftIO . throwIO . userError $ "newTransaction: no signers given"
+newTransaction signers@(payer : _) instructions = do
   bh <- getTheLatestBlockhash
-  signedTx <- either (liftIO . throwIO) pure (newTxInt bh)
+  signedTx <-
+    either
+      (liftIO . throwIO)
+      pure
+      (newTransactionIntentWithPayer (toSolanaPublicKey payer) signers instructions bh)
   sendTransaction signedTx
 
 -- | Configuration used to fetch the nonce account in 'newNonceTransaction':
@@ -65,6 +85,15 @@
 cfgNonceAccountConfirmed :: ConfigurationObject
 cfgNonceAccountConfirmed = cfgJustEncodingBase64 {commitment = Just "confirmed"}
 
+-- | Configuration used to submit the transaction in 'newNonceTransaction':
+-- 'defaultRpcSendTransactionConfig' with the preflight simulation pinned at
+-- the commitment the nonce account is read at ('cfgNonceAccountConfirmed').
+-- The node's default @finalized@ preflight bank may not yet hold the nonce
+-- value the transaction was built against (or the account at all) right
+-- after creation or an advance, and rejects the send with @BlockhashNotFound@.
+cfgNonceSendConfirmed :: ConfigurationObject
+cfgNonceSendConfirmed = defaultRpcSendTransactionConfig {preflightCommitment = commitment cfgNonceAccountConfirmed}
+
 -- | Builds, signs, and submits a durable-nonce transaction with an
 -- explicitly named fee payer that executes the given instructions,
 -- returning its signature.
@@ -76,7 +105,11 @@
 -- 'newDurableNonceTransactionIntentWithPayer', which prepends the
 -- nonce-advance instruction ahead of the given instructions and uses the
 -- nonce account's durable nonce in place of a recent block hash (so the
--- transaction never expires, unlike 'newTransaction'). The fee payer is
+-- transaction never expires, unlike 'newTransaction'), and submits it with
+-- 'sendTransaction'' under 'cfgNonceSendConfirmed', so the node's preflight
+-- simulation runs at that same @confirmed@ commitment instead of its default
+-- @finalized@ bank (which may not yet contain the nonce value used, or the
+-- account at all, immediately after creation or an advance). The fee payer is
 -- always account 0 (sponsored fees are supported), and the given signers
 -- may be listed in any order — they must include private keys
 -- corresponding to both the payer and the nonce account's authority
@@ -105,7 +138,7 @@
         SP.NonceInitialized authority durableNonce _ -> do
           let newTxInt = newDurableNonceTransactionIntentWithPayer payer signers nonceAccount authority instructions
           signedTx <- either (liftIO . throwIO) pure (newTxInt durableNonce)
-          sendTransaction signedTx
+          sendTransaction' signedTx cfgNonceSendConfirmed
 
 -- | Estimates a priority fee (in micro-lamports per compute unit) for
 -- landing a transaction that writes to the given accounts, as the @p@-th
@@ -146,7 +179,7 @@
 -- node reports no on-chain error for it (its @err@ field is 'Nothing'); a
 -- transaction that landed but failed on-chain (e.g. a program error) yields
 -- 'False', not 'True'. Also returns 'False' if it does not confirm within
--- the poll budget.
+-- the poll budget. See 'confirmFinalized' to wait for finalization instead.
 confirmTransaction :: SolanaSignature -> Web3 Bool
 confirmTransaction sig = go (30 :: Int)
   where
@@ -161,6 +194,31 @@
         _ -> liftIO . throwIO . userError $
           "confirmTransaction: expected exactly one status for one signature, got " <> show (length statuses)
 
+-- | Polls 'Network.Solana.RPC.HTTP.Account.getSignatureStatuses' once a
+-- second, up to 60 times, until the given signature reaches @finalized@
+-- status.
+--
+-- Throws a 'userError' if the transaction finalizes with an on-chain error,
+-- or if it does not finalize within the poll budget (naming the signature in
+-- both cases). Use it before reading state through helpers that use the
+-- node's default commitment ('printBalances',
+-- 'Network.Solana.RPC.HTTP.Account.getBalance', 'getTokenAccount', ...): a
+-- transaction that 'confirmTransaction' reports at @confirmed@ is not yet
+-- visible there.
+confirmFinalized :: SolanaSignature -> Web3 ()
+confirmFinalized sig = go (60 :: Int)
+  where
+    go 0 = liftIO . throwIO . userError $ "confirmFinalized: timed out waiting for finalization of " <> show sig
+    go n = do
+      statuses <- getSignatureStatuses [sig]
+      case statuses of
+        [Just s] | confirmationStatusTxStatus s == Just "finalized" ->
+          case errTxStatus s of
+            Nothing -> pure ()
+            Just err ->
+              liftIO . throwIO . userError $ "confirmFinalized: " <> show sig <> " failed on-chain: " <> show err
+        _ -> liftIO (threadDelay 1000000) >> go (n - 1)
+
 ------------------------------------------------------------------------------------------------
 
 -- * Account-state fetch helpers
@@ -175,7 +233,7 @@
 -- failure.
 accountDataBytes :: AccountData -> Either String BS.ByteString
 accountDataBytes (AccountDataBinary bs) = Right bs
-accountDataBytes (AccountDataJSON _) = Left "account data was not base64-encoded"
+accountDataBytes AccountDataJSON {} = Left "account data was returned jsonParsed, not as bytes"
 
 -- | Fetches the given account with 'Network.Solana.RPC.HTTP.Account.getAccountInfo'
 -- and decodes its data with the given decoder, prefixing any failure message
diff --git a/src/Network/Solana/SplPrograms/Memo.hs b/src/Network/Solana/SplPrograms/Memo.hs
--- a/src/Network/Solana/SplPrograms/Memo.hs
+++ b/src/Network/Solana/SplPrograms/Memo.hs
@@ -1,5 +1,8 @@
 {-# LANGUAGE OverloadedStrings #-}
 
+-- | Client for the SPL Memo program (v2): a single instruction whose data is
+-- the memo's UTF-8 bytes; any accounts passed along must sign the
+-- transaction, which the program verifies.
 module Network.Solana.SplPrograms.Memo where
 
 import Data.Binary
diff --git a/test-integration/Main.hs b/test-integration/Main.hs
--- a/test-integration/Main.hs
+++ b/test-integration/Main.hs
@@ -16,6 +16,7 @@
 import System.IO (BufferMode (LineBuffering), hSetBuffering, stdout)
 import System.Timeout (timeout)
 import Test.Integration.Alt qualified as Alt
+import Test.Integration.Block qualified as Block
 import Test.Integration.Nonce qualified as Nonce
 import Test.Integration.PriorityFee qualified as PriorityFee
 import Test.Integration.Setup (rpcUrl)
@@ -47,7 +48,7 @@
 -- | The suite has no @-threaded@/@-N@ RTS options, so 'testGroup' already
 -- runs its children one at a time today; 'sequentialTestGroup' makes that a
 -- load-bearing property of the test tree itself rather than an accident of
--- the cabal stanza, so the five groups below (each hitting the same local
+-- the cabal stanza, so the groups below (each hitting the same local
 -- validator with fresh airdrops) can't start running concurrently if
 -- @-threaded@ is ever added. 'AllFinish' keeps every group's results visible
 -- even if an earlier one fails, matching today's behaviour.
@@ -59,4 +60,8 @@
 -- @-p@ no longer isolates just the matched test the way it would under a
 -- plain 'testGroup'.
 integrationTests :: TestTree
-integrationTests = sequentialTestGroup "integration" AllFinish [Transfer.tests, Token.tests, Nonce.tests, PriorityFee.tests, Alt.tests, WebSocket.tests]
+integrationTests =
+  sequentialTestGroup
+    "integration"
+    AllFinish
+    [Transfer.tests, Token.tests, Nonce.tests, PriorityFee.tests, Alt.tests, WebSocket.tests, Block.tests]
diff --git a/test-integration/Test/Integration/Alt.hs b/test-integration/Test/Integration/Alt.hs
--- a/test-integration/Test/Integration/Alt.hs
+++ b/test-integration/Test/Integration/Alt.hs
@@ -7,13 +7,15 @@
 import Control.Exception (throwIO)
 import Control.Monad.IO.Class (liftIO)
 import Network.Solana.Core.Crypto (createSolanaKeyPair)
-import Network.Solana.Core.VersionedMessage (altAddresses, newV0TransactionIntent)
+import Network.Solana.Core.VersionedMessage (altAddresses, newV0TransactionIntent, newV0TransactionIntentWithPayer)
 import Network.Solana.NativePrograms.AddressLookupTable (createLookupTable, extendLookupTable)
 import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
 import Network.Solana.RPC.HTTP.Account (getBalance)
 import Network.Solana.RPC.HTTP.Block (getTheLatestBlockhash)
 import Network.Solana.RPC.HTTP.Ledger (getSlot)
+import Network.Solana.RPC.HTTP.Transaction (sendTransaction)
 import Network.Solana.SolanaWeb3 (getLookupTable)
+import Network.Solana.SplPrograms.Memo qualified as Memo
 import Network.Web3.Provider (Web3)
 import Test.Integration.Setup
 import Test.Tasty
@@ -23,7 +25,9 @@
 tests =
   testGroup
     "Alt"
-    [testCase "on-chain ALT: create, extend, decode, v0 transfer through the table" (run altV0Flow)]
+    [ testCase "on-chain ALT: create, extend, decode, v0 transfer through the table" (run altV0Flow),
+      testCase "v0 memo-only transaction via explicit fee payer lands without a lookup table" (run v0MemoOnly)
+    ]
 
 -- | Creates a lookup table at the current finalized slot (guaranteed present
 -- in the SlotHashes sysvar for the on-chain create check), extends it with a
@@ -61,3 +65,17 @@
   confirmFinalized sig
   bal <- getBalance recipient
   liftIO (bal @?= 200_000_000)
+
+-- | The v0 counterpart of the legacy memo-only case: the memo's only signer
+-- is read-only, so only an explicitly named fee payer yields a valid header.
+v0MemoOnly :: Web3 ()
+v0MemoOnly = do
+  (payerPk, payerSk) <- fundedKeypair 1_000_000_000
+  bh <- getTheLatestBlockhash
+  tx <-
+    either
+      (liftIO . throwIO)
+      pure
+      (newV0TransactionIntentWithPayer payerPk [payerSk] [Memo.buildMemo "v0" [payerPk]] [] bh)
+  sig <- sendTransaction tx
+  confirmFinalized sig
diff --git a/test-integration/Test/Integration/Block.hs b/test-integration/Test/Integration/Block.hs
new file mode 100644
--- /dev/null
+++ b/test-integration/Test/Integration/Block.hs
@@ -0,0 +1,29 @@
+-- | Live coverage of the block-retrieval contract: a slot holding no block
+-- is answered by the node with a JSON-RPC error (raised as an exception the
+-- transport does not turn into 'Left'), never with 'Nothing'.
+module Test.Integration.Block (tests) where
+
+import Control.Exception (SomeException, try)
+import Data.List (isInfixOf)
+import Data.Maybe (isJust)
+import Network.Solana.RPC.HTTP.Block (getBlock)
+import Network.Solana.RPC.HTTP.Ledger (getSlot)
+import Test.Integration.Setup
+import Test.Tasty
+import Test.Tasty.HUnit
+
+tests :: TestTree
+tests =
+  testGroup
+    "Block"
+    [ testCase "getBlock on a slot holding no block raises the node's -32004 error, not Nothing" $ do
+        result <- try @SomeException (run (getSlot >>= \s -> getBlock (s + 100_000)))
+        case result of
+          Left e -> assertBool (show e) ("-32004" `isInfixOf` show e)
+          Right b -> assertFailure ("expected a JSON-RPC error, got a result (Just: " <> show (isJust b) <> ")"),
+      -- The current finalized slot: produced by the sole validator, and not yet
+      -- pruned (old slots are cleaned up under the default ledger size limit).
+      testCase "getBlock on a produced slot returns the block" $ do
+        b <- run (getSlot >>= getBlock)
+        assertBool "expected Just a block" (isJust b)
+    ]
diff --git a/test-integration/Test/Integration/Nonce.hs b/test-integration/Test/Integration/Nonce.hs
--- a/test-integration/Test/Integration/Nonce.hs
+++ b/test-integration/Test/Integration/Nonce.hs
@@ -1,15 +1,20 @@
 -- | Live durable-nonce coverage: create and initialize a nonce account, use
 -- it via 'newNonceTransaction' to send a transfer, and check the durable
--- nonce advances and the transfer lands.
+-- nonce advances and the transfer lands -- both after finalization and, as
+-- the helper promises, immediately after a merely-confirmed create or
+-- advance.
 module Test.Integration.Nonce (tests) where
 
 import Control.Exception (throwIO)
 import Control.Monad.IO.Class (liftIO)
-import Network.Solana.Core.Crypto (createSolanaKeyPair)
+import Network.Solana.Core.Account (AccountData (..), AccountInfo (dataField))
+import Network.Solana.Core.Block (BlockHash)
+import Network.Solana.Core.Crypto (SolanaPublicKey, createSolanaKeyPair)
 import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
-import Network.Solana.RPC.HTTP.Account (getBalance)
+import Network.Solana.RPC.HTTP.Account (getAccountInfo, getAccountInfo', getBalance)
 import Network.Solana.RPC.HTTP.Tokenomics (getMinimumBalanceForRentExemption)
-import Network.Solana.SolanaWeb3 (getNonceAccount, newNonceTransaction)
+import Network.Solana.RPC.HTTP.Types (defaultConfigObject, encoding, value)
+import Network.Solana.SolanaWeb3 (accountDataBytes, cfgNonceAccountConfirmed, getNonceAccount, newNonceTransaction)
 import Network.Web3.Provider (Web3)
 import Test.Integration.Setup
 import Test.Tasty
@@ -19,16 +24,21 @@
 tests =
   testGroup
     "Nonce"
-    [testCase "durable-nonce flow: create, use via newNonceTransaction, nonce advances" (run nonceFlow)]
+    [ testCase "durable-nonce flow: create, use via newNonceTransaction, nonce advances" (run nonceFlow),
+      testCase
+        "newNonceTransaction works immediately after a confirmed create and a confirmed advance"
+        (run nonceImmediateUse)
+    ]
 
 -- | Creates and initializes a nonce account (payer as authority), checks its
 -- decoded state before use, sends a transfer through 'newNonceTransaction',
 -- and checks the durable nonce advanced and the transfer landed with the
 -- exact amount.
 --
--- 'newNonceTransaction' reads the nonce account at @confirmed@ commitment
--- internally, but the node preflights its send against the @finalized@
--- bank, so the create transaction is finalized before it is called.
+-- 'getNonceAccount' reads at the node's default @finalized@ commitment, so
+-- the create transaction is finalized before its state is read;
+-- 'newNonceTransaction' itself needs only @confirmed@ state (see
+-- 'nonceImmediateUse').
 nonceFlow :: Web3 ()
 nonceFlow = do
   (payerPk, payerSk) <- fundedKeypair 2_000_000_000
@@ -40,7 +50,21 @@
       [ SystemProgram.createAccount payerPk noncePk rent 80 SystemProgram.systemProgramId,
         SystemProgram.initializeNonceAccount noncePk payerPk
       ]
-  confirmFinalized createSig -- newNonceTransaction preflights against the finalized bank
+  confirmFinalized createSig -- getNonceAccount reads the finalized bank
+  -- The node's default encoding (a bare base58 string) and the explicit
+  -- base64 pair must decode to the same 80 bytes.
+  raw <- value <$> getAccountInfo' noncePk defaultConfigObject
+  b64 <- getAccountInfo noncePk
+  liftIO (fmap dataField raw @?= fmap dataField b64)
+  -- Under encoding "jsonParsed" the node returns its parsed view for accounts
+  -- it has a parser for (the nonce account) and the base64 pair otherwise
+  -- (the payer, a plain system account with no data).
+  parsed <- value <$> getAccountInfo' noncePk (defaultConfigObject {encoding = Just "jsonParsed"})
+  case dataField <$> parsed of
+    Just (AccountDataJSON prog _ space) -> liftIO ((prog @?= "nonce") >> (space @?= 80))
+    other -> liftIO (assertFailure ("expected parsed nonce data, got " <> show other))
+  fallback <- value <$> getAccountInfo' payerPk (defaultConfigObject {encoding = Just "jsonParsed"})
+  liftIO (fmap dataField fallback @?= Just (AccountDataBinary mempty))
   before <- requireJust "nonce account (before)" =<< getNonceAccount noncePk
   nonceBefore <- case before of
     SystemProgram.NonceInitialized auth dn _ -> liftIO (auth @?= payerPk) >> pure dn
@@ -54,3 +78,50 @@
     _ -> liftIO (throwIO (userError "nonce account no longer initialized"))
   bal <- getBalance recipient
   liftIO (bal @?= 100_000_000)
+
+-- | The helper's contract: usable as soon as the nonce account's creation or
+-- last advance is merely @confirmed@, with no finalization wait. Sends two
+-- transfers back to back, the second within the finalization window of the
+-- first one's nonce advance.
+nonceImmediateUse :: Web3 ()
+nonceImmediateUse = do
+  (payerPk, payerSk) <- fundedKeypair 2_000_000_000
+  (noncePk, nonceSk) <- liftIO createSolanaKeyPair
+  rent <- getMinimumBalanceForRentExemption 80
+  _ <-
+    sendAndConfirm
+      [payerSk, nonceSk]
+      [ SystemProgram.createAccount payerPk noncePk rent 80 SystemProgram.systemProgramId,
+        SystemProgram.initializeNonceAccount noncePk payerPk
+      ]
+  nonce0 <- durableNonceAtConfirmed noncePk
+  recipient <- fst <$> liftIO createSolanaKeyPair
+  sig1 <- newNonceTransaction payerPk [payerSk] noncePk [SystemProgram.transfer payerPk recipient 100_000_000]
+  confirmOrFail "first nonce transaction" sig1
+  nonce1 <- durableNonceAtConfirmed noncePk
+  liftIO (assertBool "durable nonce advanced after the first use" (nonce1 /= nonce0))
+  sig2 <- newNonceTransaction payerPk [payerSk] noncePk [SystemProgram.transfer payerPk recipient 100_000_000]
+  confirmFinalized sig2
+  afterAcc <- requireJust "nonce account (after)" =<< getNonceAccount noncePk
+  case afterAcc of
+    SystemProgram.NonceInitialized _ dn _ ->
+      liftIO (assertBool "durable nonce advanced after the second use" (dn /= nonce1))
+    _ -> liftIO (throwIO (userError "nonce account no longer initialized"))
+  bal <- getBalance recipient
+  liftIO (bal @?= 200_000_000)
+
+-- | The nonce account's current durable nonce read at @confirmed@
+-- commitment -- the same read 'newNonceTransaction' performs.
+-- 'getNonceAccount' reads at the node's default @finalized@ commitment and
+-- would still report the pre-advance value here.
+durableNonceAtConfirmed :: SolanaPublicKey -> Web3 BlockHash
+durableNonceAtConfirmed noncePk = do
+  acc <- requireJust "nonce account (confirmed)" . value =<< getAccountInfo' noncePk cfgNonceAccountConfirmed
+  state <-
+    either
+      (liftIO . throwIO . userError)
+      pure
+      (accountDataBytes (dataField acc) >>= SystemProgram.decodeNonceAccount)
+  case state of
+    SystemProgram.NonceInitialized _ dn _ -> pure dn
+    _ -> liftIO (throwIO (userError "nonce account not initialized"))
diff --git a/test-integration/Test/Integration/PriorityFee.hs b/test-integration/Test/Integration/PriorityFee.hs
--- a/test-integration/Test/Integration/PriorityFee.hs
+++ b/test-integration/Test/Integration/PriorityFee.hs
@@ -8,7 +8,8 @@
 import Network.Solana.NativePrograms.ComputeBudget qualified as ComputeBudget
 import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
 import Network.Solana.RPC.HTTP.Account (getBalance)
-import Network.Solana.SolanaWeb3 (estimatePriorityFee)
+import Network.Solana.SolanaWeb3 (estimatePriorityFee, newTransaction)
+import Network.Solana.SplPrograms.Memo qualified as Memo
 import Network.Web3.Provider (Web3)
 import Test.Integration.Setup
 import Test.Tasty
@@ -19,7 +20,8 @@
   testGroup
     "PriorityFee"
     [ testCase "prioritized transfer lands with the exact amount" (run priorityFeeTransfer),
-      testCase "estimatePriorityFee smoke: returns without throwing" (run estimateSmoke)
+      testCase "estimatePriorityFee smoke: returns without throwing" (run estimateSmoke),
+      testCase "README priority-fee flow via newTransaction lands with its memo" (run readmePriorityFlow)
     ]
 
 -- | Sends a transfer prioritized with a compute unit limit and price, and
@@ -50,3 +52,22 @@
   pk <- fst <$> liftIO createSolanaKeyPair
   fee <- estimatePriorityFee [pk] 0.5
   liftIO (fee `seq` pure ())
+
+-- | The README's priority-fee example through the public 'newTransaction':
+-- compute-budget instructions, a transfer and a memo whose only signer is
+-- the (writable) fee payer.
+readmePriorityFlow :: Web3 ()
+readmePriorityFlow = do
+  (payerPk, payerSk) <- fundedKeypair 2_000_000_000
+  recipient <- fst <$> liftIO createSolanaKeyPair
+  sig <-
+    newTransaction
+      [payerSk]
+      [ ComputeBudget.setComputeUnitLimit 200_000,
+        ComputeBudget.setComputeUnitPrice 10_000,
+        SystemProgram.transfer payerPk recipient 1_000_000_000,
+        Memo.buildMemo "thanks for the coffee" [payerPk]
+      ]
+  confirmFinalized sig
+  bal <- getBalance recipient
+  liftIO (bal @?= 1_000_000_000)
diff --git a/test-integration/Test/Integration/Setup.hs b/test-integration/Test/Integration/Setup.hs
--- a/test-integration/Test/Integration/Setup.hs
+++ b/test-integration/Test/Integration/Setup.hs
@@ -10,9 +10,10 @@
 -- before returning (later sends preflight against the finalized bank), and
 -- 'sendAndConfirm' (via 'sendConfirmedPreflight') pins preflight at
 -- @confirmed@ so multi-step flows can build on merely-confirmed intermediate
--- state. Callers are expected to 'confirmFinalized' the last transaction of
--- a flow before asserting on account state or balances (finalization is
--- monotone by slot, so one wait covers every prior transaction).
+-- state. Callers are expected to 'confirmFinalized' (re-exported from
+-- "Network.Solana.SolanaWeb3") the last transaction of a flow before
+-- asserting on account state or balances (finalization is monotone by slot,
+-- so one wait covers every prior transaction).
 module Test.Integration.Setup
   ( rpcUrl,
     wsEndpoint,
@@ -27,7 +28,6 @@
   )
 where
 
-import Control.Concurrent (threadDelay)
 import Control.Exception (throwIO)
 import Control.Monad.IO.Class (liftIO)
 import Data.List (stripPrefix)
@@ -36,11 +36,11 @@
 import Network.Solana.Core.Crypto (SolanaPrivateKey, SolanaPublicKey, SolanaSignature, createSolanaKeyPair, toSolanaPublicKey)
 import Network.Solana.Core.Instruction (Instruction)
 import Network.Solana.Core.Message (newTransactionIntentWithPayer)
-import Network.Solana.RPC.HTTP.Account (confirmationStatusTxStatus, errTxStatus, getSignatureStatuses)
+import Network.Solana.RPC.HTTP.Account (errTxStatus, getSignatureStatuses)
 import Network.Solana.RPC.HTTP.Block (getTheLatestBlockhash)
 import Network.Solana.RPC.HTTP.Transaction (requestAirdrop, sendTransaction')
 import Network.Solana.RPC.HTTP.Types (defaultConfigObject, encoding, preflightCommitment)
-import Network.Solana.SolanaWeb3 (confirmTransaction)
+import Network.Solana.SolanaWeb3 (confirmFinalized, confirmTransaction)
 import Network.Web3.Provider (Provider (HttpProvider), Web3, runWeb3')
 import System.Environment (lookupEnv)
 
@@ -117,25 +117,6 @@
         [Just s] | Just err <- errTxStatus s ->
           liftIO . throwIO . userError $ what <> " failed on-chain: " <> show sig <> ": " <> show err
         _ -> liftIO . throwIO . userError $ what <> " failed to confirm: " <> show sig
-
--- | Polls 'getSignatureStatuses' once a second, up to 60 times, until the
--- given signature reaches @finalized@ status.
---
--- Throws a 'userError' if the transaction finalizes with an on-chain error,
--- or if it does not finalize within the poll budget (naming the signature in
--- both cases).
-confirmFinalized :: SolanaSignature -> Web3 ()
-confirmFinalized sig = go (60 :: Int)
-  where
-    go 0 = liftIO . throwIO . userError $ "confirmFinalized: timed out waiting for finalization of " <> show sig
-    go n = do
-      statuses <- getSignatureStatuses [sig]
-      case statuses of
-        [Just s] | confirmationStatusTxStatus s == Just "finalized" ->
-          case errTxStatus s of
-            Nothing -> pure ()
-            Just err -> liftIO . throwIO . userError $ "confirmFinalized: " <> show sig <> " failed on-chain: " <> show err
-        _ -> liftIO (threadDelay 1000000) >> go (n - 1)
 
 -- | Sends an already-encoded transaction with preflight pinned at
 -- @confirmed@ -- the suite's one commitment override, single-sourced here so
diff --git a/test-integration/Test/Integration/Token.hs b/test-integration/Test/Integration/Token.hs
--- a/test-integration/Test/Integration/Token.hs
+++ b/test-integration/Test/Integration/Token.hs
@@ -7,7 +7,7 @@
 import Network.Solana.Core.Crypto (createSolanaKeyPair)
 import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
 import Network.Solana.RPC.HTTP.Tokenomics (getMinimumBalanceForRentExemption)
-import Network.Solana.SolanaWeb3 (getMint, getTokenAccount)
+import Network.Solana.SolanaWeb3 (getMint, getTokenAccount, newTransaction)
 import Network.Solana.SplPrograms.AssociatedTokenAccount qualified as ATA
 import Network.Solana.SplPrograms.Token qualified as Token
 import Network.Web3.Provider (Web3)
@@ -19,7 +19,9 @@
 tests =
   testGroup
     "Token"
-    [testCase "mint -> ATAs -> mintTo -> transferChecked, decoded state matches" (run tokenLifecycle)]
+    [ testCase "mint -> ATAs -> mintTo -> transferChecked, decoded state matches" (run tokenLifecycle),
+      testCase "README SPL flow via newTransaction: setup tx, then idempotent ATA + transferChecked" (run readmeSplFlow)
+    ]
 
 -- | Creates a mint (payer as mint authority, no freeze authority), derives
 -- the associated token accounts for the payer and a second wallet, mints
@@ -51,3 +53,37 @@
   liftIO ((Token.taAmount accA @?= 750_000) >> (Token.taMint accA @?= mintPk) >> (Token.taOwner accA @?= payerPk))
   accB <- requireJust "token account B" =<< getTokenAccount ataB
   liftIO ((Token.taAmount accB @?= 250_000) >> (Token.taOwner accB @?= walletB))
+
+-- | The README's SPL example, structurally verbatim: one setup transaction
+-- (createAccount + initializeMint2 + createAssociatedTokenAccount + mintTo,
+-- signed by the payer and the mint) and one transfer transaction
+-- (createAssociatedTokenAccountIdempotent + transferChecked), both through
+-- the public 'newTransaction' rather than the suite's 'sendAndConfirm'.
+readmeSplFlow :: Web3 ()
+readmeSplFlow = do
+  (payerPk, payerSk) <- fundedKeypair 3_000_000_000
+  (mintPk, mintSk) <- liftIO createSolanaKeyPair
+  recipient <- fst <$> liftIO createSolanaKeyPair
+  sourceAta <- requireJust "source ATA derivation" (ATA.getAssociatedTokenAddress payerPk mintPk)
+  destinationAta <- requireJust "destination ATA derivation" (ATA.getAssociatedTokenAddress recipient mintPk)
+  mintRent <- getMinimumBalanceForRentExemption 82
+  setupTx <-
+    newTransaction
+      [payerSk, mintSk]
+      [ SystemProgram.createAccount payerPk mintPk mintRent 82 Token.tokenProgramId,
+        Token.initializeMint2 mintPk 6 payerPk Nothing,
+        ATA.createAssociatedTokenAccount payerPk payerPk mintPk,
+        Token.mintTo mintPk sourceAta payerPk [] 10_000_000
+      ]
+  confirmFinalized setupTx
+  transferTx <-
+    newTransaction
+      [payerSk]
+      [ ATA.createAssociatedTokenAccountIdempotent payerPk recipient mintPk,
+        Token.transferChecked sourceAta mintPk destinationAta payerPk [] 1_000_000 6
+      ]
+  confirmFinalized transferTx
+  source <- requireJust "source token account" =<< getTokenAccount sourceAta
+  liftIO (Token.taAmount source @?= 9_000_000)
+  destination <- requireJust "destination token account" =<< getTokenAccount destinationAta
+  liftIO (Token.taAmount destination @?= 1_000_000)
diff --git a/test-integration/Test/Integration/Transfer.hs b/test-integration/Test/Integration/Transfer.hs
--- a/test-integration/Test/Integration/Transfer.hs
+++ b/test-integration/Test/Integration/Transfer.hs
@@ -1,11 +1,14 @@
 -- | Live SOL transfer coverage: a plain transfer from a freshly airdropped
--- payer, and a sponsored transfer where the fee payer and the transfer's
--- signer are different accounts.
+-- payer, a sponsored transfer where the fee payer and the transfer's signer
+-- are different accounts, and the fee-payer contract of the public
+-- 'newTransaction' helper (first key pays, read-only-signer-only
+-- instructions land, empty signer list rejected).
 module Test.Integration.Transfer (tests) where
 
-import Control.Exception (throwIO)
+import Control.Exception (SomeException, throwIO, try)
 import Control.Monad (void)
 import Control.Monad.IO.Class (liftIO)
+import Data.List (isInfixOf)
 import Network.Solana.Core.Crypto (createSolanaKeyPair)
 import Network.Solana.Core.Message (newTransactionIntentWithPayer)
 import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
@@ -14,6 +17,7 @@
 import Network.Solana.RPC.HTTP.Chain (getVersion)
 import Network.Solana.RPC.HTTP.Transaction (sendTransaction)
 import Network.Solana.SolanaWeb3 (newTransaction)
+import Network.Solana.SplPrograms.Memo qualified as Memo
 import Network.Web3.Provider (Web3)
 import Test.Integration.Setup
 import Test.Tasty
@@ -25,11 +29,14 @@
     "Transfer"
     [ testCase "getVersion answers" (run (void getVersion)),
       testCase "airdropped SOL transfer lands with the exact amount" (run basicTransfer),
-      testCase "sponsored transfer: sponsor pays the fee, signer order is free" (run sponsoredTransfer)
+      testCase "sponsored transfer: sponsor pays the fee, signer order is free" (run sponsoredTransfer),
+      testCase "newTransaction: memo-only instruction (read-only authority signer) lands" (run memoOnly),
+      testCase "newTransaction: empty signer list is rejected before any RPC call" noSigners,
+      testCase "newTransaction: first key pays even when unreferenced, signer order is free" (run firstKeyPays)
     ]
 
 -- | Airdrops a payer, sends it through 'newTransaction' (which builds its
--- own blockhash and derives the fee payer from signer order), and checks the
+-- own blockhash and names its first key as the fee payer), and checks the
 -- recipient receives exactly the transferred amount. Live-covers
 -- 'newTransaction' with every dependency (airdrop, blockhash, confirmation)
 -- finalized.
@@ -41,6 +48,10 @@
   confirmFinalized sig
   bal <- getBalance recipient
   liftIO (bal @?= 1_000_000_000)
+  -- The README's sequence: balances read right after confirmFinalized reflect
+  -- the transfer on both sides.
+  senderBal <- getBalance payerPk
+  liftIO (assertBool "sender paid the transfer and the fee" (senderBal < 1_000_000_000))
 
 -- | A sponsor pays the fee for a transfer sent by another funded account, with
 -- the private keys deliberately passed in the wrong order to
@@ -63,6 +74,47 @@
       pure
       (newTransactionIntentWithPayer sponsorPk [senderSk, sponsorSk] [SystemProgram.transfer senderPk recipient 500_000_000] bh)
   sig <- sendTransaction tx
+  confirmFinalized sig
+  recipientBal <- getBalance recipient
+  liftIO (recipientBal @?= 500_000_000)
+  senderBal <- getBalance senderPk
+  liftIO (senderBal @?= 500_000_000) -- sender paid NO fee: exactly the transfer left
+  sponsorBal <- getBalance sponsorPk
+  liftIO (assertBool "sponsor paid the fee" (sponsorBal < 2_000_000_000))
+
+-- | A memo instruction's only account is its signer as a /read-only/ signer,
+-- so a fee payer derived from the instructions alone would be read-only and
+-- the node would reject the transaction at sanitize time. 'newTransaction'
+-- must name its first key as the (writable) fee payer instead.
+memoOnly :: Web3 ()
+memoOnly = do
+  (payerPk, payerSk) <- fundedKeypair 1_000_000_000
+  sig <- newTransaction [payerSk] [Memo.buildMemo "solana-haskell-sdk" [payerPk]]
+  confirmFinalized sig
+
+-- | With no signing key there is no fee payer; 'newTransaction' must say so
+-- before touching the network rather than submit a signature-less
+-- transaction for the node to reject.
+noSigners :: Assertion
+noSigners = do
+  pk <- fst <$> createSolanaKeyPair
+  recipient <- fst <$> createSolanaKeyPair
+  r <- try @SomeException (run (newTransaction [] [SystemProgram.transfer pk recipient 1]))
+  case r of
+    Left e -> assertBool ("expected a \"no signers\" error, got: " <> show e) ("no signers" `isInfixOf` show e)
+    Right sig -> assertFailure ("sent a transaction with no signers: " <> show sig)
+
+-- | The first key given to 'newTransaction' pays the fee even if no
+-- instruction references it (sponsored fees), and the remaining keys may be
+-- passed in any order.
+firstKeyPays :: Web3 ()
+firstKeyPays = do
+  pairs <- fundedKeypairs [2_000_000_000, 1_000_000_000]
+  ((sponsorPk, sponsorSk), (senderPk, senderSk)) <- case pairs of
+    [a, b] -> pure (a, b)
+    _ -> liftIO (throwIO (userError "expected two keypairs"))
+  recipient <- fst <$> liftIO createSolanaKeyPair
+  sig <- newTransaction [sponsorSk, senderSk] [SystemProgram.transfer senderPk recipient 500_000_000]
   confirmFinalized sig
   recipientBal <- getBalance recipient
   liftIO (recipientBal @?= 500_000_000)
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -19,7 +19,10 @@
 import Test.NativePrograms.Vote qualified
 import Test.RPC.Chain qualified
 import Test.RPC.Parsers qualified
+import Test.RPC.Types qualified
 import Test.RPC.WebSocket qualified
+import Test.Readme qualified
+import Test.SolanaWeb3 qualified
 import Test.SplPrograms.AssociatedTokenAccount qualified
 import Test.SplPrograms.Memo qualified
 import Test.SplPrograms.Token qualified
@@ -49,7 +52,10 @@
           Test.NativePrograms.Vote.tests,
           Test.RPC.Chain.tests,
           Test.RPC.Parsers.tests,
+          Test.RPC.Types.tests,
           Test.RPC.WebSocket.tests,
+          Test.Readme.tests,
+          Test.SolanaWeb3.tests,
           Test.SplPrograms.AssociatedTokenAccount.tests,
           Test.SplPrograms.Memo.tests,
           Test.SplPrograms.Token.tests
diff --git a/test/Test/Core/Account.hs b/test/Test/Core/Account.hs
--- a/test/Test/Core/Account.hs
+++ b/test/Test/Core/Account.hs
@@ -2,11 +2,36 @@
 
 module Test.Core.Account (tests) where
 
-import Data.Aeson (eitherDecode)
+import Data.Aeson (eitherDecode, encode)
+import Data.Aeson.Types (parseMaybe, withObject, (.:))
+import Data.ByteString qualified as BS
+import Data.ByteString.Lazy qualified as BL
+import Data.Either (isLeft)
+import Data.List (isInfixOf)
+import Data.Word (Word8)
 import Network.Solana.Core.Account
 import Test.Tasty
 import Test.Tasty.HUnit
+import Test.Tasty.QuickCheck
 
+-- | The Rent sysvar's 17 data bytes (the cluster-independent defaults), as
+-- Agave returns them: bare base58 under the default encoding, a tagged pair
+-- under @base64@.
+rentBytes :: BS.ByteString
+rentBytes = BS.pack [152, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 50]
+
+-- | A nonce account's @data@ under @encoding: "jsonParsed"@, as Agave 2.1.16
+-- returns it.
+nonceParsedJson :: BL.ByteString
+nonceParsedJson =
+  "{\"parsed\":{\"info\":{\"authority\":\"AkagUZWfCDrEDJTtsuxvAGv9AkhNQAgywJLxyzHPnFQ9\",\"blockhash\":\"EKp95XWYEyvEKaNoZMqaBBBiHPuEyodG9ZC4iHiKHMjj\",\"feeCalculator\":{\"lamportsPerSignature\":\"5000\"}},\"type\":\"initialized\"},\"program\":\"nonce\",\"space\":80}"
+
+-- | The Clock sysvar as a whole @getAccountInfo@ value under
+-- @encoding: "jsonParsed"@ (the shape that failed at @$.value.data@).
+clockAccountJson :: BL.ByteString
+clockAccountJson =
+  "{\"data\":{\"parsed\":{\"info\":{\"epoch\":0,\"epochStartTimestamp\":1789286435,\"leaderScheduleEpoch\":1,\"slot\":1367,\"unixTimestamp\":1789287077},\"type\":\"clock\"},\"program\":\"sysvar\",\"space\":40},\"executable\":false,\"lamports\":1169280,\"owner\":\"Sysvar1111111111111111111111111111111111111\",\"rentEpoch\":0,\"space\":40}"
+
 tests :: TestTree
 tests =
   testGroup
@@ -18,5 +43,51 @@
       testCase "AccountData FromJSON rejects invalid base58 in a base58-tagged pair" $
         case eitherDecode "[\"0OIl\",\"base58\"]" :: Either String AccountData of
           Left _ -> pure ()
-          Right ad -> assertFailure ("expected parse failure, got " <> show ad)
+          Right ad -> assertFailure ("expected parse failure, got " <> show ad),
+      testCase "AccountData FromJSON decodes a bare string as base58 (the node's default binary encoding)" $
+        eitherDecode "\"2RsdFKVyfoKRJwMEPcvasdsF\"" @?= Right (AccountDataBinary rentBytes),
+      testCase "bare string and base58-tagged pair decode identically" $ do
+        eitherDecode "\"1111\"" @?= Right (AccountDataBinary (BS.replicate 4 0))
+        eitherDecode "[\"1111\",\"base58\"]" @?= Right (AccountDataBinary (BS.replicate 4 0)),
+      testCase "base64-tagged pair still decodes as base64" $
+        eitherDecode "[\"mA0AAAAAAAAAAAAAAAAAQDI=\",\"base64\"]" @?= Right (AccountDataBinary rentBytes),
+      testCase "bare empty string decodes to empty account data" $
+        eitherDecode "\"\"" @?= Right (AccountDataBinary BS.empty),
+      testCase "AccountData FromJSON rejects a bare string that is not base58" $
+        case eitherDecode "\"0OIl\"" :: Either String AccountData of
+          Left err -> assertBool ("expected \"invalid base58\" in: " <> err) ("invalid base58" `isInfixOf` err)
+          Right ad -> assertFailure ("expected parse failure, got " <> show ad),
+      testProperty "AccountData JSON round-trip (ToJSON emits the bare base58 form)" $ \(ws :: [Word8]) ->
+        let bs = BS.pack ws
+         in eitherDecode (encode (AccountDataBinary bs)) === Right (AccountDataBinary bs),
+      testCase "AccountData FromJSON decodes a jsonParsed object into AccountDataJSON" $
+        case eitherDecode nonceParsedJson of
+          Left err -> assertFailure err
+          Right (AccountDataJSON prog parsed space) -> do
+            prog @?= "nonce"
+            space @?= 80
+            parseMaybe (withObject "parsed" (.: "type")) parsed @?= Just ("initialized" :: String)
+          Right other -> assertFailure ("expected AccountDataJSON, got " <> show other),
+      testCase "AccountData FromJSON decodes the jsonParsed base64 fallback pair as binary" $
+        eitherDecode "[\"c3lzdGVtX3Byb2dyYW0=\",\"base64\"]" @?= Right (AccountDataBinary "system_program"),
+      testCase "AccountData FromJSON rejects a jsonParsed object missing space" $
+        assertBool
+          "accepted an object without space"
+          (isLeft (eitherDecode "{\"parsed\":{},\"program\":\"nonce\"}" :: Either String AccountData)),
+      testCase "AccountData FromJSON rejects the never-emitted [text, \"jsonParsed\"] pair" $
+        assertBool
+          "accepted a jsonParsed pair"
+          (isLeft (eitherDecode "[\"{}\",\"jsonParsed\"]" :: Either String AccountData)),
+      testCase "AccountData ToJSON/FromJSON round-trips parsed data" $
+        case eitherDecode nonceParsedJson :: Either String AccountData of
+          Left err -> assertFailure err
+          Right ad -> eitherDecode (encode ad) @?= Right ad,
+      testCase "AccountInfo FromJSON accepts a jsonParsed account value" $
+        case eitherDecode clockAccountJson :: Either String AccountInfo of
+          Left err -> assertFailure err
+          Right info -> do
+            lamports info @?= Lamport 1169280
+            case dataField info of
+              AccountDataJSON prog _ space -> (prog @?= "sysvar") >> (space @?= 40)
+              other -> assertFailure ("expected AccountDataJSON, got " <> show other)
     ]
diff --git a/test/Test/Core/Crypto.hs b/test/Test/Core/Crypto.hs
--- a/test/Test/Core/Crypto.hs
+++ b/test/Test/Core/Crypto.hs
@@ -2,9 +2,12 @@
 
 module Test.Core.Crypto (tests) where
 
+import Control.Exception (ErrorCall, IOException, evaluate, try)
 import Data.Aeson (eitherDecode)
 import Data.Binary (decode, encode)
 import Data.ByteString qualified as BS
+import Data.Either (isLeft)
+import Data.List (isInfixOf)
 import Network.Solana.Core.Crypto
 import Test.Tasty
 import Test.Tasty.HUnit
@@ -16,6 +19,13 @@
 instance Arbitrary Bytes32 where
   arbitrary = Bytes32 . BS.pack <$> vectorOf 32 arbitrary
 
+-- | The keypair derived from a seed of 32 one-bytes; its 64 secret-key bytes
+-- are what @test/fixtures/keypair.json@ holds in @solana-keygen@ format.
+fixtureKeypair :: (SolanaPublicKey, SolanaPrivateKey)
+fixtureKeypair = case createSolanaKeypairFromSeed (BS.replicate 32 1) of
+  Just kp -> kp
+  Nothing -> error "fixtureKeypair: 32-byte seed rejected"
+
 tests :: TestTree
 tests =
   testGroup
@@ -45,5 +55,84 @@
       testCase "SolanaSignature FromJSON rejects invalid base58" $
         case eitherDecode "\"0OIl\"" :: Either String SolanaSignature of
           Left _ -> pure ()
-          Right sig -> assertFailure ("expected parse failure, got " <> show sig)
+          Right sig -> assertFailure ("expected parse failure, got " <> show sig),
+      testGroup
+        "mkPrivateKeyFromBytes"
+        [ testCase "accepts a genuine 64-byte secret key" $ do
+            let (pk, sk) = fixtureKeypair
+            mkPrivateKeyFromBytes (getSolanaPrivateKeyRaw sk) @?= Right sk
+            fmap toSolanaPublicKey (mkPrivateKeyFromBytes (getSolanaPrivateKeyRaw sk)) @?= Right pk,
+          testCase "rejects empty, truncated, seed-only and over-long input" $
+            mapM_
+              (\bs -> assertBool ("accepted " <> show (BS.length bs) <> " bytes") (isLeft (mkPrivateKeyFromBytes bs)))
+              [BS.empty, BS.pack [1], BS.replicate 32 1, BS.replicate 63 1, BS.replicate 65 1],
+          testCase "rejects a mismatched public-key half" $ do
+            let raw = getSolanaPrivateKeyRaw (snd fixtureKeypair)
+                corrupted = BS.init raw <> BS.singleton (BS.last raw + 1)
+            assertBool
+              "accepted a key whose public half is not derived from its seed"
+              (isLeft (mkPrivateKeyFromBytes corrupted)),
+          testProperty "rejects every length other than 64" $
+            forAll (choose (0, 130) `suchThat` (/= 64)) $ \n ->
+              forAll (vectorOf n arbitrary) $ \ws -> isLeft (mkPrivateKeyFromBytes (BS.pack ws)),
+          testProperty "rejects random 64-byte input" $
+            forAll (vectorOf 64 arbitrary) $ \ws -> isLeft (mkPrivateKeyFromBytes (BS.pack ws)),
+          testCase "mkPrivateKeyFromString applies the same checks to Base58 input" $ do
+            let raw = getSolanaPrivateKeyRaw (snd fixtureKeypair)
+                corrupted = BS.take 32 raw <> BS.replicate 32 9
+            mkPrivateKeyFromString (toBase58String raw) @?= Right (snd fixtureKeypair)
+            assertBool
+              "accepted a Base58 key whose public half is not derived from its seed"
+              (isLeft (mkPrivateKeyFromString (toBase58String corrupted)))
+        ],
+      testGroup
+        "readSigningKeyFromFile"
+        [ testCase "loads a solana-keygen keypair file" $ do
+            sk <- readSigningKeyFromFile "test/fixtures/keypair.json"
+            sk @?= snd fixtureKeypair
+            show (toSolanaPublicKey sk) @?= "AKnL4NNf3DGWZJS6cPknBuEGnVsV4A4m5tgebLHaRSZ9"
+            dverify (toSolanaPublicKey sk) "solana-haskell-sdk" (dsign sk "solana-haskell-sdk") @?= True,
+          testCase "rejects a truncated key file" $ do
+            r <- try (readSigningKeyFromFile "test/fixtures/keypair_truncated.json")
+            case r of
+              Left (_ :: IOException) -> pure ()
+              Right _ -> assertFailure "accepted a 1-byte key file",
+          testCase "rejects out-of-range byte values" $ do
+            r <- try (readSigningKeyFromFile "test/fixtures/keypair_out_of_range.json")
+            case r of
+              Left (_ :: IOException) -> pure ()
+              Right _ -> assertFailure "accepted a key file with an entry of 256",
+          -- A JSON parser's syntax error quotes the unparsed remainder of its
+          -- input; for a key file that would put secret bytes into an exception
+          -- applications routinely log.
+          testCase "does not echo the file's contents in the error for a malformed file" $ do
+            r <- try (readSigningKeyFromFile "test/fixtures/keypair_syntax_error.json")
+            case r of
+              Left (e :: IOException) -> do
+                assertBool ("unexpected message: " <> show e) ("not a JSON array of 64 integers" `isInfixOf` show e)
+                assertBool
+                  ("key bytes leaked into: " <> show e)
+                  (not ("1,1,1" `isInfixOf` show e) && not ("138" `isInfixOf` show e))
+              Right _ -> assertFailure "accepted a malformed key file"
+        ],
+      testGroup
+        "raw constructors"
+        [ testCase "unsafeSolanaPrivateKeyRaw calls error on a wrong-length input" $ do
+            r <- try (evaluate (unsafeSolanaPrivateKeyRaw [1]))
+            case r of
+              Left (_ :: ErrorCall) -> pure ()
+              Right _ -> assertFailure "built a 1-byte private key",
+          testCase "unsafeSolanaPublicKeyRaw calls error on a wrong-length input" $ do
+            r <- try (evaluate (unsafeSolanaPublicKeyRaw (replicate 33 0)))
+            case r of
+              Left (_ :: ErrorCall) -> pure ()
+              Right _ -> assertFailure "built a 33-byte public key",
+          testCase "unsafeSolanaPrivateKey calls error on a mismatched public-key half" $ do
+            let raw = getSolanaPrivateKeyRaw (snd fixtureKeypair)
+                corrupted = toBase58String (BS.take 32 raw <> BS.replicate 32 9)
+            r <- try (evaluate (unsafeSolanaPrivateKey corrupted))
+            case r of
+              Left (_ :: ErrorCall) -> pure ()
+              Right _ -> assertFailure "built a private key whose public half is not derived from its seed"
+        ]
     ]
diff --git a/test/Test/Core/Instruction.hs b/test/Test/Core/Instruction.hs
--- a/test/Test/Core/Instruction.hs
+++ b/test/Test/Core/Instruction.hs
@@ -3,14 +3,20 @@
 module Test.Core.Instruction (tests) where
 
 import Data.Aeson (eitherDecode)
+import Data.Binary (encode)
+import Data.ByteString.Lazy qualified as BL
+import Data.Either (isRight)
+import Data.List (isInfixOf)
 import Network.Solana.Core.Crypto (SolanaPublicKey, unsafeSolanaPublicKeyRaw)
 import Network.Solana.Core.Instruction
 import Test.Tasty
 import Test.Tasty.HUnit
+import Test.Tasty.QuickCheck
 
-progPk, accPk :: SolanaPublicKey
+progPk, accPk, fillerKey :: SolanaPublicKey
 progPk = unsafeSolanaPublicKeyRaw (replicate 32 11)
 accPk = unsafeSolanaPublicKeyRaw (replicate 32 12)
+fillerKey = unsafeSolanaPublicKeyRaw (replicate 32 50)
 
 tests :: TestTree
 tests =
@@ -24,5 +30,28 @@
       testCase "CompiledInstruction FromJSON rejects invalid base58 data" $
         case eitherDecode "{\"programIdIndex\":0,\"accounts\":[0,1],\"data\":\"0OIl\"}" :: Either String CompiledInstruction of
           Left _ -> pure ()
-          Right _ -> assertFailure "expected parse failure on invalid base58"
+          Right _ -> assertFailure "expected parse failure on invalid base58",
+      testCase "compileInstruction rejects an account at index 256 instead of wrapping it" $ do
+        let keys = replicate 256 fillerKey <> [accPk]
+            ix = mkInstruction fillerKey [AccountMeta accPk False False] ()
+        case compileInstruction keys ix of
+          Left (MissingIndex msg) -> assertBool ("expected \"overflow\" in: " <> msg) ("overflow" `isInfixOf` msg)
+          Right _ -> assertFailure "compiled an account index of 256",
+      testCase "compileInstruction rejects a program id at index 256" $ do
+        let keys = replicate 256 fillerKey <> [progPk]
+            ix = mkInstruction progPk [AccountMeta fillerKey False False] ()
+        case compileInstruction keys ix of
+          Left (MissingIndex msg) -> assertBool ("expected \"overflow\" in: " <> msg) ("overflow" `isInfixOf` msg)
+          Right _ -> assertFailure "compiled a program id index of 256",
+      testCase "compileInstruction keeps index 255 (boundary)" $ do
+        let keys = replicate 255 fillerKey <> [accPk]
+            ix = mkInstruction fillerKey [AccountMeta accPk False False] ()
+        case compileInstruction keys ix of
+          Left err -> assertFailure (show err)
+          Right ci -> BL.unpack (encode ci) @?= [0, 1, 255, 0],
+      testProperty "compileInstruction succeeds exactly when the key position fits in a byte" $
+        forAll (chooseInt (0, 600)) $ \i ->
+          let keys = replicate i fillerKey <> [accPk]
+              ix = mkInstruction accPk [AccountMeta accPk False False] ()
+           in isRight (compileInstruction keys ix) === (i <= 255)
     ]
diff --git a/test/Test/Core/Message.hs b/test/Test/Core/Message.hs
--- a/test/Test/Core/Message.hs
+++ b/test/Test/Core/Message.hs
@@ -103,6 +103,24 @@
             counterexample "writable key in readonly section" (property (not (any writableOf (sr <> ur))))
           ]
 
+-- | 'mkNewMessageWithPayer' must pin the named payer to account 0 as a
+-- writable signer whatever the instructions declare (or fail to declare)
+-- about it.
+prop_payerInvariants :: Property
+prop_payerInvariants =
+  forAll (resize 5 (listOf1 genInstruction)) $ \instrs ->
+    forAll (elements keyPool) $ \payer ->
+      let msg = mkNewMessageWithPayer payer fixedBlockhash instrs
+          hdr = mHeader msg
+          keys = mAccountKeys msg
+       in conjoin
+            [ counterexample "payer is not account 0" (take 1 keys === [payer]),
+              counterexample
+                "no writable signer"
+                (property (numReadonlySignedAccounts hdr < numRequiredSignatures hdr)),
+              counterexample "duplicate keys" (keys === nub keys)
+            ]
+
 tests :: TestTree
 tests =
   testGroup
@@ -233,5 +251,49 @@
         case newDurableNonceTransactionIntentWithPayer sponsorPk [sponsorPriv, authorityPriv] noncePk authorityPk [] durableNonceBh of
           Left err -> assertFailure (show err)
           Right b64 -> BS.head (fromBase64String b64) @?= 2,
-      testProperty "message header/key-ordering invariants" prop_messageInvariants
+      testProperty "message header/key-ordering invariants" prop_messageInvariants,
+      testCase "memo-only transaction via explicit fee payer matches Rust" $ do
+        fs <- loadFixtures "test/fixtures/transactions.json"
+        let ix = Memo.buildMemo "hello-memo" [fst payerKeys]
+        case newTransactionIntentWithPayer (fst payerKeys) [snd payerKeys] [ix] fixedBlockhash of
+          Left err -> assertFailure (show err)
+          Right b64 -> b64 @?= toBase64String (requireFixture "memo-only-transaction" fs),
+      testCase "memo-only message: explicit fee payer seeds a writable signer, instruction-derived payer does not" $ do
+        let ix = Memo.buildMemo "hello-memo" [fst payerKeys]
+        mHeader (mkNewMessageWithPayer (fst payerKeys) fixedBlockhash [ix]) @?= MessageHeader 1 0 1
+        mHeader (mkNewMessage fixedBlockhash [ix]) @?= MessageHeader 1 1 1,
+      testProperty "explicit fee payer is account 0 and a writable signer" prop_payerInvariants,
+      testCase "orderSigningKeys: permuted keys are ordered to the message's required signers" $ do
+        let ix = SP.createAccount (fst payerKeys) (fst newAccountKeys) 1000000 165 ownerPk
+            msg = mkNewMessageWithPayer (fst newAccountKeys) fixedBlockhash [ix]
+        case orderSigningKeys msg [snd payerKeys, snd newAccountKeys] of
+          Left err -> assertFailure (show err)
+          Right ordered -> map toSolanaPublicKey ordered @?= take 2 (mAccountKeys msg),
+      testCase "orderSigningKeys: missing and unused keys are reported" $ do
+        let ix = SP.createAccount (fst payerKeys) (fst newAccountKeys) 1000000 165 ownerPk
+            msg = mkNewMessageWithPayer (fst newAccountKeys) fixedBlockhash [ix]
+        case orderSigningKeys msg [snd payerKeys] of
+          Right _ -> assertFailure "expected Left for missing signer"
+          Left (MissingIndex msg') ->
+            assertBool ("expected \"missing signer\" in: " <> msg') ("missing signer" `isInfixOf` msg')
+        case orderSigningKeys msg [snd payerKeys, snd newAccountKeys, snd extraKeys] of
+          Right _ -> assertFailure "expected Left for unused signing key"
+          Left (MissingIndex msg') ->
+            assertBool ("expected \"unused signing key\" in: " <> msg') ("unused signing key" `isInfixOf` msg'),
+      testCase "a message with more than 256 account keys fails to compile instead of wrapping indices" $ do
+        let metas = [AccountMeta (unsafeSolanaPublicKeyRaw (replicate 31 7 <> [b])) False False | b <- [0 .. 254]]
+            ix = mkInstruction Memo.memoProgramId (AccountMeta (fst payerKeys) True True : metas) ()
+        case newMessage fixedBlockhash [ix] of
+          Left (MissingIndex msg) -> assertBool ("expected \"overflow\" in: " <> msg) ("overflow" `isInfixOf` msg)
+          Right _ -> assertFailure "compiled a message with 257 account keys"
+        case newTransactionIntentWithPayer (fst payerKeys) [snd payerKeys] [ix] fixedBlockhash of
+          Left (MissingIndex msg) -> assertBool ("expected \"overflow\" in: " <> msg) ("overflow" `isInfixOf` msg)
+          Right _ -> assertFailure "signed a message with 257 account keys",
+      testCase "a message with exactly 256 account keys compiles and its header does not wrap" $ do
+        let metas = [AccountMeta (unsafeSolanaPublicKeyRaw (replicate 31 7 <> [b])) False False | b <- [0 .. 253]]
+            ix = mkInstruction Memo.memoProgramId (AccountMeta (fst payerKeys) True True : metas) ()
+        numReadonlyUnsignedAccounts (mHeader (mkNewMessage fixedBlockhash [ix])) @?= 255
+        case newMessage fixedBlockhash [ix] of
+          Left err -> assertFailure (show err)
+          Right _ -> pure ()
     ]
diff --git a/test/Test/Core/VersionedMessage.hs b/test/Test/Core/VersionedMessage.hs
--- a/test/Test/Core/VersionedMessage.hs
+++ b/test/Test/Core/VersionedMessage.hs
@@ -10,6 +10,7 @@
 import Network.Solana.Core.VersionedMessage
 import Network.Solana.NativePrograms.AddressLookupTable qualified as ALT
 import Network.Solana.NativePrograms.SystemProgram qualified as SP
+import Network.Solana.SplPrograms.Memo qualified as Memo
 import Test.Fixtures
 import Test.Tasty
 import Test.Tasty.HUnit
@@ -23,9 +24,24 @@
     Just kp -> kp
     Nothing -> error "failed to derive payer keypair from seed"
 
+newAccountKeys :: (SolanaPublicKey, SolanaPrivateKey)
+newAccountKeys =
+  case createSolanaKeypairFromSeed (BS.replicate 32 10) of
+    Just kp -> kp
+    Nothing -> error "failed to derive new-account keypair from seed"
+
+extraKeys :: (SolanaPublicKey, SolanaPrivateKey)
+extraKeys =
+  case createSolanaKeypairFromSeed (BS.replicate 32 40) of
+    Just kp -> kp
+    Nothing -> error "failed to derive extra keypair from seed"
+
 recipientPk :: SolanaPublicKey
 recipientPk = unsafeSolanaPublicKeyRaw (replicate 32 2)
 
+ownerPk :: SolanaPublicKey
+ownerPk = unsafeSolanaPublicKeyRaw (replicate 32 5)
+
 addr29 :: SolanaPublicKey
 addr29 = unsafeSolanaPublicKeyRaw (replicate 32 29)
 
@@ -137,8 +153,71 @@
                   ]
             case compileV0Message fixedBlockhash ixs [table] of
               Left err -> assertFailure (show err)
-              Right bytes -> bytes @?= requireFixture "v0-message" txFs
+              Right bytes -> bytes @?= requireFixture "v0-message" txFs,
+      testCase "v0 signed transaction via explicit fee payer matches Rust" $ do
+        fs <- loadFixtures "test/fixtures/transactions.json"
+        let ixs =
+              [ SP.transfer (fst payerKeys) recipientPk 1000000000,
+                SP.transfer (fst payerKeys) addr29 500000
+              ]
+        case newV0TransactionIntentWithPayer (fst payerKeys) [snd payerKeys] ixs [lookupTable] fixedBlockhash of
+          Left err -> assertFailure (show err)
+          Right b64 -> b64 @?= toBase64String (requireFixture "v0-transfer-transaction" fs),
+      testCase "v0 memo-only transaction via explicit fee payer matches Rust" $ do
+        fs <- loadFixtures "test/fixtures/transactions.json"
+        let ix = Memo.buildMemo "hello-memo" [fst payerKeys]
+        case newV0TransactionIntentWithPayer (fst payerKeys) [snd payerKeys] [ix] [] fixedBlockhash of
+          Left err -> assertFailure (show err)
+          Right b64 -> b64 @?= toBase64String (requireFixture "v0-memo-only-transaction" fs),
+      testCase "v0 memo-only message: explicit fee payer seeds a writable signer, compileV0Message does not" $ do
+        let ix = Memo.buildMemo "hello-memo" [fst payerKeys]
+        case compileV0MessageWithPayer (fst payerKeys) fixedBlockhash [ix] [] of
+          Left err -> assertFailure (show err)
+          Right bytes -> BS.take 4 bytes @?= BS.pack [0x80, 1, 0, 1]
+        case compileV0Message fixedBlockhash [ix] [] of
+          Left err -> assertFailure (show err)
+          Right bytes -> BS.take 4 bytes @?= BS.pack [0x80, 1, 1, 1],
+      testCase "v0 explicit fee payer: signers may be given in any order" $ do
+        let ix = SP.createAccount (fst payerKeys) (fst newAccountKeys) 1000000 165 ownerPk
+            sign keys = newV0TransactionIntentWithPayer (fst payerKeys) keys [ix] [] fixedBlockhash
+        case (sign [snd newAccountKeys, snd payerKeys], sign [snd payerKeys, snd newAccountKeys]) of
+          (Right p, Right o) -> p @?= o
+          (Left err, _) -> assertFailure (show err)
+          (_, Left err) -> assertFailure (show err),
+      testCase "v0 explicit fee payer: missing and unused signing keys are reported" $ do
+        let ix = SP.createAccount (fst payerKeys) (fst newAccountKeys) 1000000 165 ownerPk
+        case newV0TransactionIntentWithPayer (fst payerKeys) [snd payerKeys] [ix] [] fixedBlockhash of
+          Right _ -> assertFailure "expected Left for missing signer"
+          Left (MissingIndex msg) ->
+            assertBool ("expected \"missing signer\" in: " <> msg) ("missing signer" `isInfixOf` msg)
+        let tooManyKeys = [snd payerKeys, snd newAccountKeys, snd extraKeys]
+        case newV0TransactionIntentWithPayer (fst payerKeys) tooManyKeys [ix] [] fixedBlockhash of
+          Right _ -> assertFailure "expected Left for unused signing key"
+          Left (MissingIndex msg) ->
+            assertBool ("expected \"unused signing key\" in: " <> msg) ("unused signing key" `isInfixOf` msg),
+      testCase "static and table-loaded keys totalling more than 256 fail to compile" $ do
+        -- Each table stays under 256 addresses (the per-table check passes);
+        -- 2 static keys + 300 loaded keys exceed what a byte index can address.
+        let tableA = AddressLookupTableAccount tableKey [numberedKey b | b <- [0 .. 199]]
+            tableB = AddressLookupTableAccount otherTableKey [numberedKey b | b <- [200 .. 299]]
+            metas = [AccountMeta (numberedKey b) False True | b <- [0 .. 299]]
+            ix = mkInstruction dummyProgramId (AccountMeta (fst payerKeys) True True : metas) ()
+        case compileV0Message fixedBlockhash [ix] [tableA, tableB] of
+          Left (MissingIndex msg) ->
+            assertBool ("expected \"account index overflow\" in: " <> msg) ("account index overflow" `isInfixOf` msg)
+          Right _ -> assertFailure "compiled a v0 message resolving more than 256 keys",
+      testCase "static plus table-loaded keys totalling exactly 256 compile" $ do
+        let table = AddressLookupTableAccount tableKey [numberedKey b | b <- [0 .. 253]]
+            metas = [AccountMeta (numberedKey b) False True | b <- [0 .. 253]]
+            ix = mkInstruction dummyProgramId (AccountMeta (fst payerKeys) True True : metas) ()
+        case compileV0Message fixedBlockhash [ix] [table] of
+          Left err -> assertFailure (show err)
+          Right _ -> pure ()
     ]
+
+-- | A distinct 32-byte key per number (up to 65535), for large key sets.
+numberedKey :: Int -> SolanaPublicKey
+numberedKey b = unsafeSolanaPublicKeyRaw (2 : fromIntegral (b `div` 256) : fromIntegral (b `mod` 256) : replicate 29 0)
 
 -- | Compare two compile results by their message bytes ('CompileException'
 -- has no 'Eq' instance to compare), failing loudly if either side failed.
diff --git a/test/Test/Metaplex/TokenMetadata.hs b/test/Test/Metaplex/TokenMetadata.hs
--- a/test/Test/Metaplex/TokenMetadata.hs
+++ b/test/Test/Metaplex/TokenMetadata.hs
@@ -16,9 +16,6 @@
 import Network.Solana.Core.Crypto (SolanaPublicKey, createSolanaKeypairFromSeed, getSolanaPublicKeyRaw, unsafeSolanaPublicKeyRaw)
 import Network.Solana.Core.Instruction (AccountMeta (..), iAccounts)
 import Network.Solana.Metaplex.TokenMetadata qualified as TM
-import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
-import Network.Solana.SplPrograms.Token qualified as Token
-import Network.Solana.Sysvar qualified as Sysvar
 import Test.Fixtures
 import Test.Tasty
 import Test.Tasty.HUnit
@@ -66,8 +63,9 @@
     }
 
 -- metadata_instruction_data.json mixes two shapes in one array: six
--- {name, hex} entries (the golden vectors) and one {name, accounts} entry
--- (create-v3-full-accounts). Test.Fixtures.loadFixtures decodes the whole
+-- {name, hex} entries (the golden vectors) and two {name, accounts} entries
+-- (create-v3-full-accounts, master-edition-some-accounts).
+-- Test.Fixtures.loadFixtures decodes the whole
 -- file as [Fixture], which requires every element to carry a "hex" field, so
 -- it can't be used directly here. Load the file as [Value] instead and pick
 -- out each shape locally, without extending the shared loader.
@@ -79,8 +77,8 @@
   vals <- either fail pure =<< eitherDecodeFileStrict path
   pure (mapMaybe (parseMaybe parseJSON) (vals :: [Value]))
 
--- Local decode of the `create-v3-full-accounts` entry (ground truth for the
--- createMetadataAccountV3 meta test).
+-- Local decode of the {name, accounts} entries (ground truth for the
+-- builder meta tests).
 
 data FixtureAccountMeta = FixtureAccountMeta T.Text Bool Bool
 
@@ -97,12 +95,20 @@
   parseJSON = withObject "AccountsFixture" $ \v ->
     AccountsFixture <$> v .: "name" <*> v .: "accounts"
 
-loadCreateV3FullAccounts :: FilePath -> IO [AccountMeta]
-loadCreateV3FullAccounts path = do
+-- | The {name, accounts} entries of the given fixture file; elements of the
+-- other shape are skipped.
+loadAccountsFixtures :: FilePath -> IO [AccountsFixture]
+loadAccountsFixtures path = do
   vals <- either fail pure =<< eitherDecodeFileStrict path
-  case find ((== "create-v3-full-accounts") . afName) (mapMaybe (parseMaybe parseJSON) (vals :: [Value])) of
-    Just af -> pure (map toAccountMeta (afAccounts af))
-    Nothing -> fail "create-v3-full-accounts entry not found"
+  pure (mapMaybe (parseMaybe parseJSON) (vals :: [Value]))
+
+-- | The account metas of the named {name, accounts} entry; calls 'error' if
+-- it is missing (mirroring 'requireFixture').
+requireAccounts :: String -> [AccountsFixture] -> [AccountMeta]
+requireAccounts name afs =
+  case find ((== name) . afName) afs of
+    Just af -> map toAccountMeta (afAccounts af)
+    Nothing -> error ("accounts fixture not found: " <> name)
   where
     toAccountMeta (FixtureAccountMeta hexPubkey signer writable) =
       AccountMeta
@@ -110,7 +116,8 @@
           isSigner = signer,
           isWritable = writable
         }
-    decodeHex hexPubkey = either (error . ("bad hex in create-v3-full-accounts: " <>)) id (B16.decode (TE.encodeUtf8 hexPubkey))
+    decodeHex hexPubkey =
+      either (error . (("bad hex in " <> name <> ": ") <>)) id (B16.decode (TE.encodeUtf8 hexPubkey))
 
 -- Small QuickCheck generators covering every support type and instruction
 -- variant, for the round-trip property below.
@@ -165,11 +172,14 @@
 enc :: TM.TokenMetadataInstruction -> BS.ByteString
 enc = BL.toStrict . encode
 
+accountsFixturePath :: FilePath
+accountsFixturePath = "test/fixtures/metadata_instruction_data.json"
+
 tests :: TestTree
 tests =
   withResource (loadDataFixtures "test/fixtures/metadata_instruction_data.json") (const (pure ())) $ \getFixtures ->
     withResource (loadFixtures "test/fixtures/pda.json") (const (pure ())) $ \getPdaFixtures ->
-      withResource (loadCreateV3FullAccounts "test/fixtures/metadata_instruction_data.json") (const (pure ())) $ \getCreateV3Accounts ->
+      withResource (loadAccountsFixtures accountsFixturePath) (const (pure ())) $ \getAccountsFixtures ->
         withResource (loadFixtures "test/fixtures/state_fixtures.json") (const (pure ())) $ \getStateFixtures ->
           testGroup
             "Metaplex Token Metadata"
@@ -266,7 +276,7 @@
               testGroup
                 "builder metas"
                 [ testCase "createMetadataAccountV3 matches create-v3-full-accounts fixture" $ do
-                    expected <- getCreateV3Accounts
+                    expected <- requireAccounts "create-v3-full-accounts" <$> getAccountsFixtures
                     iAccounts (TM.createMetadataAccountV3 mintPk payerPk payerPk payerPk True dataV2Full True (Just (TM.CollectionDetailsV1 0)))
                       @?= expected,
                   testCase "updateMetadataAccountV2 metas" $
@@ -277,21 +287,9 @@
                           @?= [ AccountMeta {accountPubKey = metadataAddr, isSigner = False, isWritable = True},
                                 AccountMeta {accountPubKey = payerPk, isSigner = True, isWritable = False}
                               ],
-                  testCase "createMasterEditionV3 metas" $
-                    case (TM.deriveMasterEditionAddress mintPk, TM.deriveMetadataAddress mintPk) of
-                      (Just editionAddr, Just metadataAddr) ->
-                        iAccounts (TM.createMasterEditionV3 mintPk payerPk payerPk payerPk (Just 100))
-                          @?= [ AccountMeta {accountPubKey = editionAddr, isSigner = False, isWritable = True},
-                                AccountMeta {accountPubKey = mintPk, isSigner = False, isWritable = True},
-                                AccountMeta {accountPubKey = payerPk, isSigner = True, isWritable = False},
-                                AccountMeta {accountPubKey = payerPk, isSigner = True, isWritable = False},
-                                AccountMeta {accountPubKey = payerPk, isSigner = True, isWritable = True},
-                                AccountMeta {accountPubKey = metadataAddr, isSigner = False, isWritable = False},
-                                AccountMeta {accountPubKey = Token.tokenProgramId, isSigner = False, isWritable = False},
-                                AccountMeta {accountPubKey = SystemProgram.systemProgramId, isSigner = False, isWritable = False},
-                                AccountMeta {accountPubKey = Sysvar.rent, isSigner = False, isWritable = False}
-                              ]
-                      _ -> assertFailure "PDA derivation failed"
+                  testCase "createMasterEditionV3 matches master-edition-some-accounts fixture" $ do
+                    expected <- requireAccounts "master-edition-some-accounts" <$> getAccountsFixtures
+                    iAccounts (TM.createMasterEditionV3 mintPk payerPk payerPk payerPk (Just 100)) @?= expected
                 ]
             ]
   where
diff --git a/test/Test/RPC/Chain.hs b/test/Test/RPC/Chain.hs
--- a/test/Test/RPC/Chain.hs
+++ b/test/Test/RPC/Chain.hs
@@ -1,11 +1,17 @@
+{-# LANGUAGE OverloadedStrings #-}
+
 module Test.RPC.Chain (tests) where
 
-import Network.Solana.RPC.HTTP.Chain (percentilePriorityFee)
+import Data.Aeson (eitherDecode)
+import Network.Solana.RPC.HTTP.Chain (PerformanceSample (..), SolanaVersion (..), percentilePriorityFee)
 import Test.Tasty
 import Test.Tasty.HUnit
 
 tests :: TestTree
-tests =
+tests = testGroup "Network.Solana.RPC.HTTP.Chain" [percentileTests, sampleTests, versionTests]
+
+percentileTests :: TestTree
+percentileTests =
   testGroup
     "percentilePriorityFee"
     [ testCase "empty samples -> 0" $ percentilePriorityFee 0.5 [] @?= 0,
@@ -17,4 +23,40 @@
       testCase "negative p clamps to 0" $ percentilePriorityFee (-1) [9] @?= 9,
       testCase "p above 1 clamps to 1" $ percentilePriorityFee 2 [1, 9] @?= 9,
       testCase "zeros filtered before ranking" $ percentilePriorityFee 0.5 [0, 5, 0, 1] @?= 1
+    ]
+
+-- | Upstream @RpcPerfSample.num_non_vote_transactions@ is an @Option@: a
+-- current node reports @null@ for samples recorded before it started
+-- tracking the field.
+sampleTests :: TestTree
+sampleTests =
+  testGroup
+    "PerformanceSample"
+    [ testCase "numNonVoteTransactions omitted parses as Nothing" $
+        case eitherDecode (sample "") of
+          Left err -> assertFailure err
+          Right s -> numNonVoteTransactions s @?= Nothing,
+      testCase "numNonVoteTransactions null parses as Nothing" $
+        case eitherDecode (sample ",\"numNonVoteTransactions\":null") of
+          Left err -> assertFailure err
+          Right s -> numNonVoteTransactions s @?= Nothing,
+      testCase "numNonVoteTransactions present is kept" $
+        case eitherDecode (sample ",\"numNonVoteTransactions\":4") of
+          Left err -> assertFailure err
+          Right s -> numNonVoteTransactions s @?= Just 4
+    ]
+  where
+    -- A sample's mandatory fields, plus whatever tail the case under test needs.
+    sample tail' = "{\"slot\":1,\"numTransactions\":2,\"numSlots\":3,\"samplePeriodSecs\":60" <> tail' <> "}"
+
+-- | Upstream @RpcVersionInfo.feature_set@ is an @Option@ as well.
+versionTests :: TestTree
+versionTests =
+  testGroup
+    "SolanaVersion"
+    [ testCase "feature-set omitted parses as Nothing" $
+        eitherDecode "{\"solana-core\":\"2.1.16\"}" @?= Right (SolanaVersion "2.1.16" Nothing),
+      testCase "feature-set present is kept" $
+        eitherDecode "{\"solana-core\":\"2.1.16\",\"feature-set\":3271415109}"
+          @?= Right (SolanaVersion "2.1.16" (Just 3271415109))
     ]
diff --git a/test/Test/RPC/Parsers.hs b/test/Test/RPC/Parsers.hs
--- a/test/Test/RPC/Parsers.hs
+++ b/test/Test/RPC/Parsers.hs
@@ -19,8 +19,17 @@
 
 import Data.Aeson (FromJSON, Value)
 import Data.Aeson.Types (parseEither, parseJSON)
+import Data.Map.Strict qualified as M
 import Data.Maybe (isJust)
-import Network.Solana.Core.Account (Account, AccountInfo, Lamport (..), executable, lamports)
+import Network.Solana.Core.Account
+  ( Account,
+    AccountData (..),
+    AccountInfo,
+    Lamport (..),
+    dataField,
+    executable,
+    lamports,
+  )
 import Network.Solana.Core.Block (BlockHash, BlockHeight)
 import Network.Solana.Core.Crypto (SolanaPublicKey)
 import Network.Solana.RPC.HTTP.Account hiding (lamports)
@@ -32,6 +41,7 @@
 import Network.Solana.RPC.HTTP.Tokenomics
 import Network.Solana.RPC.HTTP.Transaction
 import Network.Solana.RPC.HTTP.Types
+import Network.Solana.SplPrograms.Token (decodeMint, mDecimals, mSupply)
 import Test.Fixtures
 import Test.Tasty
 import Test.Tasty.HUnit
@@ -79,7 +89,14 @@
     testCase "getHealth" $ withResult @String "getHealth" $ \health ->
       health @?= "ok",
     testCase "getRecentPerformanceSamples" $ withResult @[PerformanceSample] "getRecentPerformanceSamples" $ \samples ->
-      assertBool "samples cover a non-zero period" (all ((> 0) . samplePeriodSecs) samples)
+      assertBool "samples cover a non-zero period" (all ((> 0) . samplePeriodSecs) samples),
+    testCase "getHighestSnapshotSlot" $ withResult @HighestSnapshotSlot "getHighestSnapshotSlot" $ \s ->
+      assertBool "a full snapshot exists" (full s > 0),
+    testCase "getRecentPrioritizationFees" $ withResult @[PrioritizationFee] "getRecentPrioritizationFees" $ \fees ->
+      assertBool "recent slots are sampled" (not (null fees) && length fees <= 150),
+    testCase "getRecentPrioritizationFees (address filter)" $
+      withResult @[PrioritizationFee] "getRecentPrioritizationFees-filtered" $ \fees ->
+        assertBool "recent slots are sampled" (not (null fees))
   ]
 
 ledgerTests :: [TestTree]
@@ -99,7 +116,24 @@
     testCase "getFirstAvailableBlock" $ withResult @Slot "getFirstAvailableBlock" $ \_ ->
       pure (),
     testCase "getStakeMinimumDelegation" $ withResult @(RPCResponse Lamport) "getStakeMinimumDelegation" $ \r ->
-      assertBool "context slot is populated" (contextSlot (context r) > 0)
+      assertBool "context slot is populated" (contextSlot (context r) > 0),
+    -- A single-validator cluster: the schedule names exactly the node itself.
+    testCase "getLeaderSchedule" $ withResult @NodeIdentity "getIdentity" $ \node ->
+      withResult @(Maybe LeaderSchedule) "getLeaderSchedule" $ \case
+        Nothing -> assertFailure "expected a schedule for the current epoch"
+        Just schedule -> do
+          M.keys schedule @?= [identity node]
+          assertBool "every leader has slots" (all (not . null) (M.elems schedule)),
+    testCase "getSlotLeader" $ withResult @SolanaPublicKey "getSlotLeader" $ \_ ->
+      pure (),
+    testCase "getSlotLeaders" $ withResult @[SolanaPublicKey] "getSlotLeaders" $ \leaders ->
+      length leaders @?= 3, -- the recorder asks for three
+    testCase "getMaxRetransmitSlot" $ withResult @Slot "getMaxRetransmitSlot" $ \_ ->
+      pure (),
+    testCase "getMaxShredInsertSlot" $ withResult @Slot "getMaxShredInsertSlot" $ \_ ->
+      pure (),
+    testCase "minimumLedgerSlot" $ withResult @Slot "minimumLedgerSlot" $ \_ ->
+      pure ()
   ]
 
 blockTests :: [TestTree]
@@ -119,7 +153,11 @@
       case value r of
         BlockProduction identities _ -> assertBool "at least one leader produced blocks" (not (null identities)),
     testCase "getBlocks" $ withResult @[Slot] "getBlocks" $ \slots ->
-      assertBool "the queried range is non-empty" (not (null slots))
+      assertBool "the queried range is non-empty" (not (null slots)),
+    testCase "getBlocksWithLimit" $ withResult @[Slot] "getBlocksWithLimit" $ \slots ->
+      assertBool "at most the requested limit of three" (not (null slots) && length slots <= 3),
+    testCase "getBlockTime" $ withResult @(Maybe Int) "getBlockTime" $ \t ->
+      assertBool "the block carries a timestamp" (maybe False (> 0) t)
   ]
 
 tokenomicsTests :: [TestTree]
@@ -133,7 +171,13 @@
     testCase "getVoteAccounts" $ withResult @VoteAccounts "getVoteAccounts" $ \accounts ->
       assertBool "the test validator votes" (not (null (current accounts))),
     testCase "getMinimumBalanceForRentExemption" $ withResult @Lamport "getMinimumBalanceForRentExemption" $ \rent ->
-      assertBool "rent exemption for 165 bytes is non-trivial" (rent > Lamport 1000000)
+      assertBool "rent exemption for 165 bytes is non-trivial" (rent > Lamport 1000000),
+    -- The bootstrap stake account's reward for the previous (32-slot) epoch.
+    testCase "getInflationReward" $ withResult @[Maybe InflationReward] "getInflationReward" $ \case
+      [Just r] -> do
+        assertBool "the bootstrap stake earned a reward" (amountReward r > Lamport 0)
+        assertBool "post balance includes the reward" (postBalance r > amountReward r)
+      other -> assertFailure ("expected exactly one reward, got " <> show (length other))
   ]
 
 accountTests :: [TestTree]
@@ -155,7 +199,28 @@
     testCase "getLargestAccounts" $ withResult @(RPCResponse [AddressAndLamports]) "getLargestAccounts" $ \r ->
       assertBool "accounts are listed with balances" (not (null (value r)) && all ((> Lamport 0) . RpcAccount.lamports) (value r)),
     testCase "getProgramAccounts" $ withResult @[Account] "getProgramAccounts" $ \accounts ->
-      assertBool "the token program owns the mint and token account" (length accounts >= 2)
+      assertBool "the token program owns the mint and token account" (length accounts >= 2),
+    -- Recorded with no configuration: the node's default encoding is a bare
+    -- base58 string (the recorder's 82-byte mint).
+    testCase "getAccountInfo (node default encoding: bare base58)" $
+      withResult @(RPCResponse (Maybe AccountInfo)) "getAccountInfo-base58" $ \r ->
+        case dataField <$> value r of
+          Just (AccountDataBinary bs) -> case decodeMint bs of
+            Left e -> assertFailure e
+            Right m -> do
+              mDecimals m @?= 6
+              mSupply m @?= 42000000
+          other -> assertFailure ("expected binary mint data, got " <> show other),
+    testCase "getAccountInfo (jsonParsed)" $
+      withResult @(RPCResponse (Maybe AccountInfo)) "getAccountInfo-jsonParsed" $ \r ->
+        case dataField <$> value r of
+          Just (AccountDataJSON prog _ space) -> do
+            prog @?= "spl-token"
+            space @?= 165
+          other -> assertFailure ("expected parsed token account data, got " <> show other),
+    testCase "getAccountInfo (jsonParsed falls back to base64 without a parser)" $
+      withResult @(RPCResponse (Maybe AccountInfo)) "getAccountInfo-jsonParsed-fallback" $ \r ->
+        fmap dataField (value r) @?= Just (AccountDataBinary "")
   ]
 
 transactionTests :: [TestTree]
@@ -172,7 +237,10 @@
           confirmationStatusTxStatus s @?= Just "finalized"
         other -> assertFailure ("expected exactly one status, got " <> show (length other)),
     testCase "getTransaction" $ withResult @(Maybe TransactionResult) "getTransaction" $ \result ->
-      assertBool "the recorded transfer is retrievable" (isJust result)
+      assertBool "the recorded transfer is retrievable" (isJust result),
+    -- One signature at the test validator's default fee.
+    testCase "getFeeForMessage" $ withResult @(RPCResponse (Maybe Int)) "getFeeForMessage" $ \r ->
+      value r @?= Just 5000
   ]
 
 tokenTests :: [TestTree]
@@ -190,5 +258,8 @@
         [] -> assertFailure "expected the minted account to be listed"
         (a : _) -> amount' a @?= "42000000",
     testCase "getTokenAccountsByOwner" $ withResult @(RPCResponse [Account]) "getTokenAccountsByOwner" $ \r ->
+      length (value r) @?= 1,
+    -- The recorder approves the recipient as delegate of the one token account.
+    testCase "getTokenAccountsByDelegate" $ withResult @(RPCResponse [Account]) "getTokenAccountsByDelegate" $ \r ->
       length (value r) @?= 1
   ]
diff --git a/test/Test/RPC/Types.hs b/test/Test/RPC/Types.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/RPC/Types.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | Hand-written response shapes for "Network.Solana.RPC.HTTP.Types" that a
+-- local validator never produces (older nodes and RPC proxies do), so they
+-- cannot live in the recorded-fixture suite "Test.RPC.Parsers".
+module Test.RPC.Types (tests) where
+
+import Data.Aeson (eitherDecode)
+import Network.Solana.RPC.HTTP.Types
+import Test.Tasty
+import Test.Tasty.HUnit
+
+tests :: TestTree
+tests =
+  testGroup
+    "RPC types"
+    [ testCase "Context without apiVersion parses" $
+        case eitherDecode "{\"slot\":41}" :: Either String Context of
+          Left err -> assertFailure err
+          Right ctx -> do
+            apiVersion ctx @?= Nothing
+            contextSlot ctx @?= 41,
+      testCase "Context with apiVersion null parses as Nothing" $
+        case eitherDecode "{\"apiVersion\":null,\"slot\":41}" :: Either String Context of
+          Left err -> assertFailure err
+          Right ctx -> apiVersion ctx @?= Nothing,
+      testCase "Context keeps apiVersion when present" $
+        case eitherDecode "{\"apiVersion\":\"2.1.16\",\"slot\":41}" :: Either String Context of
+          Left err -> assertFailure err
+          Right ctx -> apiVersion ctx @?= Just "2.1.16",
+      testCase "RPCResponse without context.apiVersion still yields its value" $
+        case eitherDecode "{\"context\":{\"slot\":41},\"value\":7}" :: Either String (RPCResponse Int) of
+          Left err -> assertFailure err
+          Right r -> value r @?= 7
+    ]
diff --git a/test/Test/RPC/WebSocket.hs b/test/Test/RPC/WebSocket.hs
--- a/test/Test/RPC/WebSocket.hs
+++ b/test/Test/RPC/WebSocket.hs
@@ -119,7 +119,13 @@
     testCase "an unknown notification method is rejected rather than misread" $
       assertBool
         "expected a Left"
-        (isLeft (parseWsMessage "{\"jsonrpc\":\"2.0\",\"method\":\"slotNotification\",\"params\":{\"result\":{\"slot\":1},\"subscription\":1}}"))
+        (isLeft (parseWsMessage "{\"jsonrpc\":\"2.0\",\"method\":\"slotNotification\",\"params\":{\"result\":{\"slot\":1},\"subscription\":1}}")),
+    -- The node always sends err (null on success); a value without it is
+    -- malformed and must not read as a success.
+    testCase "signature notification value without an err key is rejected" $
+      assertBool
+        "expected a Left"
+        (isLeft (parseWsMessage "{\"jsonrpc\":\"2.0\",\"method\":\"signatureNotification\",\"params\":{\"result\":{\"context\":{\"slot\":5},\"value\":{}},\"subscription\":1}}"))
   ]
 
 -- | A 'WsTransport' that replays a fixed script of incoming frames and
@@ -182,7 +188,17 @@
     testCase "times out when the node never answers" $ do
       (transport, _) <- scriptedTransport []
       result <- awaitSignature transport (RequestId 1) Nothing 1 (unsafeSigFromString docSignature)
-      assertBool ("expected a timeout, got " <> show result) (either ("timed out" `isInfixOf`) (const False) result)
+      assertBool ("expected a timeout, got " <> show result) (either ("timed out" `isInfixOf`) (const False) result),
+    testCase "does not report success for a notification lacking err" $ do
+      (transport, _) <-
+        scriptedTransport
+          [ ack,
+            "{\"jsonrpc\":\"2.0\",\"method\":\"signatureNotification\",\"params\":{\"result\":{\"context\":{\"slot\":5},\"value\":{}},\"subscription\":24006}}"
+          ]
+      result <- awaitSignature transport (RequestId 1) Nothing 5 (unsafeSigFromString docSignature)
+      assertBool
+        ("expected a parse failure naming the missing key, got " <> show result)
+        (either (\e -> "err" `isInfixOf` e && not ("timed out" `isInfixOf` e)) (const False) result)
   ]
 
 isLeft :: Either a b -> Bool
diff --git a/test/Test/Readme.hs b/test/Test/Readme.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/Readme.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | Keeps the README's usage examples and the example executables under
+-- @app/@ identical, so the text users copy is the text CI compiles.
+module Test.Readme (tests) where
+
+import Data.ByteString qualified as BS
+import Data.Text (Text)
+import Data.Text qualified as T
+import Data.Text.Encoding qualified as TE
+import Test.Tasty
+import Test.Tasty.HUnit
+
+readUtf8 :: FilePath -> IO Text
+readUtf8 path = TE.decodeUtf8 <$> BS.readFile path
+
+-- | The fenced Haskell blocks of the README that are complete programs (they
+-- open with a LANGUAGE pragma), in order of appearance.
+programBlocks :: Text -> [Text]
+programBlocks = go . T.lines
+  where
+    go [] = []
+    go (l : ls)
+      | l == "```haskell" =
+          let (body, rest) = break (== "```") ls
+              others = go (drop 1 rest)
+           in if isProgram body then T.unlines body : others else others
+      | otherwise = go ls
+    isProgram (first : _) = "{-# LANGUAGE" `T.isPrefixOf` first
+    isProgram [] = False
+
+-- | The example executables, in the order their sources appear in the README.
+examplePrograms :: [FilePath]
+examplePrograms = ["app/Main.hs", "app/SplTransfer.hs", "app/PriorityFee.hs"]
+
+tests :: TestTree
+tests =
+  testGroup
+    "README"
+    [ testCase "usage examples are byte-identical to the compiled example programs" $ do
+        blocks <- programBlocks <$> readUtf8 "README.md"
+        programs <- mapM readUtf8 examplePrograms
+        blocks @?= programs
+    ]
diff --git a/test/Test/SolanaWeb3.hs b/test/Test/SolanaWeb3.hs
new file mode 100644
--- /dev/null
+++ b/test/Test/SolanaWeb3.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | Pure checks on the "Network.Solana.SolanaWeb3" helpers' configuration
+-- values (the helpers themselves need a node; see the integration suite).
+module Test.SolanaWeb3 (tests) where
+
+import Data.Aeson (Value (String), object, toJSON, (.=))
+import Network.Solana.RPC.HTTP.Types (commitment, preflightCommitment)
+import Network.Solana.SolanaWeb3 (cfgNonceAccountConfirmed, cfgNonceSendConfirmed)
+import Test.Tasty
+import Test.Tasty.HUnit
+
+tests :: TestTree
+tests =
+  testGroup
+    "SolanaWeb3"
+    [ testCase "newNonceTransaction preflights at the commitment it reads the nonce at" $
+        preflightCommitment cfgNonceSendConfirmed @?= commitment cfgNonceAccountConfirmed,
+      testCase "nonce commitment is confirmed (finalized/finalized would silently drop advanced-nonce sends)" $
+        commitment cfgNonceAccountConfirmed @?= Just "confirmed",
+      testCase "nonce send config wire form keeps preflight on and pins it" $
+        toJSON cfgNonceSendConfirmed
+          @?= object ["encoding" .= String "base64", "preflightCommitment" .= String "confirmed"]
+    ]
diff --git a/test/fixtures/keypair.json b/test/fixtures/keypair.json
new file mode 100644
--- /dev/null
+++ b/test/fixtures/keypair.json
@@ -0,0 +1,1 @@
+[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,138,136,227,221,116,9,241,149,253,82,219,45,60,186,93,114,202,103,9,191,29,148,18,27,243,116,136,1,180,15,111,92]
diff --git a/test/fixtures/keypair_out_of_range.json b/test/fixtures/keypair_out_of_range.json
new file mode 100644
--- /dev/null
+++ b/test/fixtures/keypair_out_of_range.json
@@ -0,0 +1,1 @@
+[256,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,138,136,227,221,116,9,241,149,253,82,219,45,60,186,93,114,202,103,9,191,29,148,18,27,243,116,136,1,180,15,111,92]
diff --git a/test/fixtures/keypair_syntax_error.json b/test/fixtures/keypair_syntax_error.json
new file mode 100644
--- /dev/null
+++ b/test/fixtures/keypair_syntax_error.json
@@ -0,0 +1,1 @@
+[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1;138,136,227,221,116,9,241,149,253,82,219,45,60,186,93,114,202,103,9,191,29,148,18,27,243,116,136,1,180,15,111,92]
diff --git a/test/fixtures/keypair_truncated.json b/test/fixtures/keypair_truncated.json
new file mode 100644
--- /dev/null
+++ b/test/fixtures/keypair_truncated.json
@@ -0,0 +1,1 @@
+[1]
diff --git a/test/fixtures/metadata_instruction_data.json b/test/fixtures/metadata_instruction_data.json
--- a/test/fixtures/metadata_instruction_data.json
+++ b/test/fixtures/metadata_instruction_data.json
@@ -57,5 +57,55 @@
       }
     ],
     "name": "create-v3-full-accounts"
+  },
+  {
+    "accounts": [
+      {
+        "pubkey": "a8b0140612ffc013e3300b768c9e666c6e1712d945bf6ca2cead99fbaa29c1e7",
+        "signer": false,
+        "writable": true
+      },
+      {
+        "pubkey": "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+        "signer": false,
+        "writable": true
+      },
+      {
+        "pubkey": "8a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c",
+        "signer": true,
+        "writable": false
+      },
+      {
+        "pubkey": "8a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c",
+        "signer": true,
+        "writable": false
+      },
+      {
+        "pubkey": "8a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c",
+        "signer": true,
+        "writable": true
+      },
+      {
+        "pubkey": "56a9c8b183e68c0582ef458b28a9f28894971e5aa21bd380aa210f6824f6ea89",
+        "signer": false,
+        "writable": true
+      },
+      {
+        "pubkey": "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9",
+        "signer": false,
+        "writable": false
+      },
+      {
+        "pubkey": "0000000000000000000000000000000000000000000000000000000000000000",
+        "signer": false,
+        "writable": false
+      },
+      {
+        "pubkey": "06a7d517192c5c51218cc94c3d4af17f58daee089ba1fd44e3dbd98a00000000",
+        "signer": false,
+        "writable": false
+      }
+    ],
+    "name": "master-edition-some-accounts"
   }
 ]
diff --git a/test/fixtures/rpc_responses.json b/test/fixtures/rpc_responses.json
--- a/test/fixtures/rpc_responses.json
+++ b/test/fixtures/rpc_responses.json
@@ -17,1143 +17,2058 @@
     "response": {
       "jsonrpc": "2.0",
       "result": {
-        "identity": "EWEDURnEjTRSa5Uz99Kf3hdThUD8X2Rv7RvMFLSQ1DCm"
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getClusterNodes",
-    "method": "getClusterNodes",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": [
-        {
-          "featureSet": 3271415109,
-          "gossip": "127.0.0.1:1024",
-          "pubkey": "EWEDURnEjTRSa5Uz99Kf3hdThUD8X2Rv7RvMFLSQ1DCm",
-          "pubsub": "127.0.0.1:8900",
-          "rpc": "127.0.0.1:8899",
-          "serveRepair": "127.0.0.1:1035",
-          "shredVersion": 24374,
-          "tpu": "127.0.0.1:1027",
-          "tpuForwards": "127.0.0.1:1028",
-          "tpuForwardsQuic": "127.0.0.1:1034",
-          "tpuQuic": "127.0.0.1:1033",
-          "tpuVote": "127.0.0.1:1029",
-          "tvu": "127.0.0.1:1025",
-          "version": "2.1.16"
-        }
-      ],
-      "id": 1
-    }
-  },
-  {
-    "name": "getHealth",
-    "method": "getHealth",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": "ok",
-      "id": 1
-    }
-  },
-  {
-    "name": "getEpochInfo",
-    "method": "getEpochInfo",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "absoluteSlot": 41,
-        "blockHeight": 41,
-        "epoch": 0,
-        "slotIndex": 41,
-        "slotsInEpoch": 432000,
-        "transactionCount": 45
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getEpochSchedule",
-    "method": "getEpochSchedule",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "firstNormalEpoch": 0,
-        "firstNormalSlot": 0,
-        "leaderScheduleSlotOffset": 432000,
-        "slotsPerEpoch": 432000,
-        "warmup": false
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getGenesisHash",
-    "method": "getGenesisHash",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": "SDdtDuPR4GB5dZDmAwuQbYTwP4x3EZcsDN4QvwJQHe4",
-      "id": 1
-    }
-  },
-  {
-    "name": "getSlot",
-    "method": "getSlot",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": 41,
-      "id": 1
-    }
-  },
-  {
-    "name": "getBlockHeight",
-    "method": "getBlockHeight",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": 41,
-      "id": 1
-    }
-  },
-  {
-    "name": "getTransactionCount",
-    "method": "getTransactionCount",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": 45,
-      "id": 1
-    }
-  },
-  {
-    "name": "getFirstAvailableBlock",
-    "method": "getFirstAvailableBlock",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": 0,
-      "id": 1
-    }
-  },
-  {
-    "name": "getRecentPerformanceSamples",
-    "method": "getRecentPerformanceSamples",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": [],
-      "id": 1
-    },
-    "params": [
-      2
-    ]
-  },
-  {
-    "name": "getStakeMinimumDelegation",
-    "method": "getStakeMinimumDelegation",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": 1000000000
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getLatestBlockhash",
-    "method": "getLatestBlockhash",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": {
-          "blockhash": "FZjZju6aDpmcT8AhLTyvt7igyL4cwTRCUsyJNoinpQgS",
-          "lastValidBlockHeight": 191
-        }
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "isBlockhashValid",
-    "method": "isBlockhashValid",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 72
-        },
-        "value": true
-      },
-      "id": 1
-    },
-    "params": [
-      "FZjZju6aDpmcT8AhLTyvt7igyL4cwTRCUsyJNoinpQgS",
-      {
-        "commitment": "processed"
-      }
-    ]
-  },
-  {
-    "name": "getBlock",
-    "method": "getBlock",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "blockHeight": 5,
-        "blockTime": 1785728550,
-        "blockhash": "EXVev5y6y5FHypiG2c1QmQ7WR7jUeU1rwesbfTS8XML3",
-        "parentSlot": 4,
-        "previousBlockhash": "4phmBxWpU7uba3moNmwyDKbH1iADu4zsUUKHbXyVbqfx",
-        "transactions": [
-          {
-            "meta": {
-              "computeUnitsConsumed": 2100,
-              "err": null,
-              "fee": 10000,
-              "innerInstructions": [],
-              "loadedAddresses": {
-                "readonly": [],
-                "writable": []
-              },
-              "logMessages": [
-                "Program Vote111111111111111111111111111111111111111 invoke [1]",
-                "Program Vote111111111111111111111111111111111111111 success"
-              ],
-              "postBalances": [
-                499999977500,
-                1000000000000000,
-                1
-              ],
-              "postTokenBalances": [],
-              "preBalances": [
-                499999987500,
-                1000000000000000,
-                1
-              ],
-              "preTokenBalances": [],
-              "rewards": null,
-              "status": {
-                "Ok": null
-              }
-            },
-            "transaction": {
-              "message": {
-                "accountKeys": [
-                  "EWEDURnEjTRSa5Uz99Kf3hdThUD8X2Rv7RvMFLSQ1DCm",
-                  "3nsvie2PSWMWitUgkKNzKqzaFEUhGahKW51HhR8ThqTc",
-                  "Vote111111111111111111111111111111111111111"
-                ],
-                "header": {
-                  "numReadonlySignedAccounts": 0,
-                  "numReadonlyUnsignedAccounts": 1,
-                  "numRequiredSignatures": 2
-                },
-                "instructions": [
-                  {
-                    "accounts": [
-                      1,
-                      1
-                    ],
-                    "data": "FMkqDfKmbTuLt2xkJs2QxzsZaVMEoSdQwbEzyF2LEjFHRAGq6Q1zFhNzyUNcBvC5DeMjm87vWA6u5RBkg5JD3XA8S9Hwq8fPEo4HS4KUfYx9viFQHaQa7xHLwfbvtP9H",
-                    "programIdIndex": 2,
-                    "stackHeight": null
-                  }
-                ],
-                "recentBlockhash": "4phmBxWpU7uba3moNmwyDKbH1iADu4zsUUKHbXyVbqfx"
-              },
-              "signatures": [
-                "4h86FydrrWzWxWnFpSBxFhbh8zbuyUcKSXUZa58Pv9Xx97oosuCdrZk5KB67QVhpDtHbwu8JoG3bx7iVW2XQagBm",
-                "9QCQT8kz1t256TtJbG7iLMKwtagGVgxbY1BubfKjdxWD5RRzqpkozRKJ9zmLNMXyAFRd7nTtMqb1yhMpkRJmxme"
-              ]
-            },
-            "version": "legacy"
-          },
-          {
-            "meta": {
-              "computeUnitsConsumed": 150,
-              "err": null,
-              "fee": 5000,
-              "innerInstructions": [],
-              "loadedAddresses": {
-                "readonly": [],
-                "writable": []
-              },
-              "logMessages": [
-                "Program 11111111111111111111111111111111 invoke [1]",
-                "Program 11111111111111111111111111111111 success"
-              ],
-              "postBalances": [
-                8999995000,
-                1000000000,
-                1
-              ],
-              "postTokenBalances": [],
-              "preBalances": [
-                10000000000,
-                0,
-                1
-              ],
-              "preTokenBalances": [],
-              "rewards": null,
-              "status": {
-                "Ok": null
-              }
-            },
-            "transaction": {
-              "message": {
-                "accountKeys": [
-                  "6o185vKXeS8D27dPfAKxJ2dNVD8iNjmRpFwdYYk3uSrT",
-                  "HR7KwDBsCkkoe9VPCuZhtwgcJMUMLMgFJb6n9WuLqyop",
-                  "11111111111111111111111111111111"
-                ],
-                "header": {
-                  "numReadonlySignedAccounts": 0,
-                  "numReadonlyUnsignedAccounts": 1,
-                  "numRequiredSignatures": 1
-                },
-                "instructions": [
-                  {
-                    "accounts": [
-                      0,
-                      1
-                    ],
-                    "data": "3Bxs3zzLZLuLQEYX",
-                    "programIdIndex": 2,
-                    "stackHeight": null
-                  }
-                ],
-                "recentBlockhash": "4phmBxWpU7uba3moNmwyDKbH1iADu4zsUUKHbXyVbqfx"
-              },
-              "signatures": [
-                "4xzhXw7xxNCGfC74NKbZNEcr92zWdGviq4GJbksRxdXz2NGYFh8Jzyox5X7trorYyYvKEnPHkfNsAfCQA5KAhFRC"
-              ]
-            },
-            "version": "legacy"
-          }
-        ]
-      },
-      "id": 1
-    },
-    "params": [
-      5,
-      {
-        "encoding": "json",
-        "maxSupportedTransactionVersion": 0,
-        "transactionDetails": "full",
-        "rewards": false
-      }
-    ]
-  },
-  {
-    "name": "getBlockCommitment",
-    "method": "getBlockCommitment",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "commitment": [
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          0,
-          999999997717120
-        ],
-        "totalStake": 999999997717120
-      },
-      "id": 1
-    },
-    "params": [
-      5
-    ]
-  },
-  {
-    "name": "getBlockProduction",
-    "method": "getBlockProduction",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": {
-          "byIdentity": {
-            "EWEDURnEjTRSa5Uz99Kf3hdThUD8X2Rv7RvMFLSQ1DCm": [
-              42,
-              42
-            ]
-          },
-          "range": {
-            "firstSlot": 0,
-            "lastSlot": 41
-          }
-        }
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getBlocks",
-    "method": "getBlocks",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": [
-        3,
-        4,
-        5
-      ],
-      "id": 1
-    },
-    "params": [
-      3,
-      5
-    ]
-  },
-  {
-    "name": "getInflationGovernor",
-    "method": "getInflationGovernor",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "foundation": 0.05,
-        "foundationTerm": 7.0,
-        "initial": 0.08,
-        "taper": 0.15,
-        "terminal": 0.015
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getInflationRate",
-    "method": "getInflationRate",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "epoch": 0,
-        "foundation": 0.004,
-        "total": 0.08,
-        "validator": 0.076
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getSupply",
-    "method": "getSupply",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": {
-          "circulating": 503000508500862375,
-          "nonCirculating": 0,
-          "nonCirculatingAccounts": [
-            "8W58E8JVJjH1jCy5CeHJQgvwFXTyAVyesuXRZGbcSUGG",
-            "DrKzW5koKSZp4mg4BdHLwr72MMXscd2kTiWgckCvvPXz",
-            "GmyW1nqYcrw7P7JqrcyP9ivU9hYNbrgZ1r5SYJJH41Fs",
-            "HbZ5FfmKWNHC7uwk6TF1hVi6TCs7dtYfdjEcuPGgzFAg",
-            "nGME7HgBT6tAJN1f6YuCCngpqT5cvSTndZUVLjQ4jwA",
-            "2WWb1gRzuXDd5viZLQF7pNRR6Y7UiyeaPpaL35X6j3ve",
-            "3ZrsTmNM6AkMcqFfv3ryfhQ2jMfqP64RQbqVyAaxqhrQ",
-            "CzAHrrrHKx9Lxf6wdCMrsZkLvk74c7J2vGv8VYPUmY6v",
-            "6o5v1HC7WhBnLfRHp8mQTtCP2khdXXjhuyGyYEoy2Suy",
-            "5khMKAcvmsFaAhoKkdg3u5abvKsmjUQNmhTNP624WB1F",
-            "4vuWt1oHRqLMhf8Nv1zyEXZsYaeK7dipwrfKLoYU9Riq",
-            "EMhn1U3TMimW3bvWYbPUvN2eZnCfsuBN4LGWhzzYhiWR",
-            "Ep5Y58PaSyALPrdFxDVAdfKtVdP55vApvsWjb3jSmXsG",
-            "HQJtLqvEGGxgNYfRXUurfxV8E1swvCnsbC3456ik27HY",
-            "5D5NxsNVTgXHyVziwV7mDFwVDS6voaBsyyGxUbhQrhNW",
-            "GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ",
-            "EMAY24PrS6rWfvpqffFCsTsFJypeeYYmtUc26wdh3Wup",
-            "P8aKfWQPeRnsZtpBrwWTYzyAoRk74KMz56xc6NEpC4J",
-            "GpxpMVhrBBBEYbEJxdR62w3daWz444V7m6dxYDZKH77D",
-            "8rT45mqpuDBR1vcnDc9kwP9DrZAXDR4ZeuKWw3u1gTGa",
-            "AsrYX4FeLXnZcrjcZmrASY2Eq1jvEeQfwxtNTxS5zojA",
-            "14FUT96s9swbmH7ZjpDvfEDywnAYy9zaNhv4xvezySGu",
-            "8pNBEppa1VcFAsx4Hzq9CpdXUXZjUXbvQwLX2K7QsCwb",
-            "CsUqV42gVQLJwQsKyjWHqGkfHarxn9hcY4YeSjgaaeTd",
-            "9S2M3UYPpnPZTBtbcUvehYmiWFK3kBhwfzV2iWuwvaVy",
-            "Ab1UcdsFXZVnkSt1Z3vcYU65GQk5MvCbs54SviaiaqHb",
-            "CY7X5o3Wi2eQhTocLmUS6JSWyx1NinBfW7AXRrkRCpi8",
-            "GK8R4uUmrawcREZ5xJy5dAzVV5V7aFvYg77id37pVTK",
-            "9xbcBZoGYFnfJZe81EDuDYKUm8xGkjzW8z4EgnVhNvsv",
-            "HuqDWJodFhAEWh6aWdsDVUqsjRket5DYXMYyDYtD8hdN",
-            "3itU5ME8L6FDqtMiRoUiT1F7PwbkTtHBbW51YWD5jtjm",
-            "5PLJZLJiRR9vf7d1JCCg7UuWjtyN9nkab9uok6TqSyuP",
-            "CUageMFi49kzoDqtdU8NvQ4Bq3sbtJygjKDAXJ45nmAi",
-            "4pV47TiPzZ7SSBPHmgUvSLmH9mMSe8tjyPhQZGbi1zPC",
-            "CVgyXrbEd1ctEuvq11QdpnCQVnPit8NLdhyqXQHLprM2",
-            "5XdtyEDREHJXXW1CTtCsVjJRjBapAwK78ZquzvnNVRrV",
-            "BsKsunvENxAraBrL77UfAn1Gi7unVEmQAdCbhsjUN6tU",
-            "7Np41oeYqPefeNQEHSv1UDhYrehxin3NStELsSKCT4K2",
-            "5q54XjQ7vDx4y6KphPeE97LUNiYGtP55spjvXAWPGBuf",
-            "3fV2GaDKa3pZxyDcpMh5Vrh2FVAMUiWUKbYmnBFv8As3",
-            "Dc2oHxFXQaC2QfLStuU7txtD3U5HZ82MrCSGDooWjbsv",
-            "3iPvAS4xdhYr6SkhVDHCLr7tJjMAFK4wvvHWJxFQVg15",
-            "Br3aeVGapRb2xTq17RU2pYZCoJpWA7bq6TKBCcYtMSmt",
-            "6yKHERk8rsbmJxvMpPuwPs1ct3hRiP7xaJF2tvnGU6nK",
-            "7Y8smnoUrYKGGuDq2uaFKVxJYhojgg7DVixHyAtGTYEV",
-            "GvpCiTgq9dmEeojCDBivoLoZqc4AkbUDACpqPMwYLWKh",
-            "CakcnaRDHka2gXyfbEd2d3xsvkJkqsLw2akB3zsN1D2S",
-            "8vqrX3H2BYLaXVintse3gorPEM4TgTwTFZNN1Fm9TdYs",
-            "3bTGcGB9F98XxnrBNftmmm48JGfPgi5sYxDEKiCjQYk3",
-            "BUnRE27mYXN9p8H1Ay24GXhJC88q2CuwLoNU2v2CrW4W",
-            "GEWSkfWgHkpiLbeKaAnwvqnECGdRNf49at5nFccVey7c",
-            "8ndGYFjav6NDXvzYcxs449Aub3AxYv4vYpk89zRDwgj7",
-            "CuatS6njAcfkFHnvai7zXCs7syA9bykXWsDCJEWfhjHG",
-            "AG3m2bAibcY8raMt4oXEGqRHwX4FWKPPJVjZxn1LySDX",
-            "GumSE5HsMV5HCwBTv2D2D81yy9x17aDkvobkqAfTRgmo",
-            "FwfaykN7ACnsEUDHANzGHqTGQZMcGnUSsahAHUqbdPrz",
-            "F9MWFw8cnYVwsRq8Am1PGfFL3cQUZV37mbGoxZftzLjN",
-            "BUjkdqUuH5Lz9XzcMcR4DdEMnFG6r8QzUMBm16Rfau96",
-            "C7C8odR8oashR5Feyrq2tJKaXL18id1dSj2zbkDGL2C2",
-            "CHmdL15akDcJgBkY6BP3hzs98Dqr6wbdDC5p8odvtSbq",
-            "FR84wZQy3Y3j2gWz6pgETUiUoJtreMEuWfbg6573UCj9",
-            "8CUUMKYNGxdgYio5CLHRHyzMEhhVRMcqefgE6dLqnVRK",
-            "AzHQ8Bia1grVVbcGyci7wzueSWkgvu7YZVZ4B9rkL5P6",
-            "63DtkW7zuARcd185EmHAkfF44bDcC2SiTSEj2spLP3iA",
-            "xQadXQiUTCCFhfHjvQx1hyJK6KVWr1w2fD6DT3cdwj7",
-            "HUAkU5psJXZuw54Lrg1ksbXzHv2fzczQ9sNbmisVMeJU",
-            "AVYpwVou2BhdLivAwLxKPALZQsY7aZNkNmGbP2fZw7RU",
-            "CWeRmXme7LmbaUWTZWFLt6FMnpzLCHaQLuR2TdgFn4Lq",
-            "Fg12tB1tz8w6zJSQ4ZAGotWoCztdMJF9hqK8R11pakog",
-            "6nN69B4uZuESZYxr9nrLDjmKRtjDZQXrehwkfQTKw62U",
-            "FiWYY85b58zEEcPtxe3PuqzWPjqBJXqdwgZeqSBmT9Cn",
-            "HCV5dGFJXRrJ3jhDYA4DCeb9TEDTwGGYXtT3wHksu2Zr",
-            "GNiz4Mq886bTNDT3pijGsu2gbw6it7sqrwncro45USeB",
-            "GK2zqSsXLA2rwVZk347RYhh6jJpRsCA69FjLW93ZGi3B",
-            "4sxwau4mdqZ8zEJsfryXq4QFYnMJSCp3HWuZQod8WU5k",
-            "H3Ni7vG1CsmJZdTvxF7RkAf9UM5qk4RsohJsmPvtZNnu",
-            "7cvkjYAkUYs4W8XcXsca7cBrEGFeSUjeZmKoNBvEwyri",
-            "Hz9nydgN1k15wnwffKX7CSmZp4VFTnTwLXAEdomFGNXy",
-            "H1rt8KvXkNhQExTRfkY8r9wjZbZ8yCih6J4wQ5Fz9HGP",
-            "Es13uD2p64UVPFpEWfDtd6SERdoNR2XVgqBQBZcZSLqW",
-            "E8jcgWvrvV7rwYHJThwfiBeQ8VAH4FgNEEMG9aAuCMAq",
-            "AzVV9ZZDxTgW4wWfJmsG6ytaHpQGSe1yz76Nyy84VbQF",
-            "Mc5XB47H3DKJHym5RLa9mPzWv5snERsF3KNv5AauXK8",
-            "9huDUZfxoJ7wGMTffUE7vh1xePqef7gyrLJu9NApncqA",
-            "CND6ZjRTzaCFVdX7pSSWgjTfHZuhxqFDoUBqWBJguNoA",
-            "JCwT5Ygmq3VeBEbDjL8s8E82Ra2rP9bq45QfZE7Xyaq7",
-            "7xJ9CLtEAcEShw9kW2gSoZkRWL566Dg12cvgzANJwbTr",
-            "DE1bawNcRJB9rVm3buyMVfr8mBEoyyu73NBovf2oXJsJ",
-            "EziVYi3Sv5kJWxmU77PnbrT8jmkVuqwdiFLLzZpLVEn7",
-            "Eyr9P5XsjK2NUKNCnfu39eqpGoiLFgVAv1LSQgMZCwiQ",
-            "CQDYc4ET2mbFhVpgj41gXahL6Exn5ZoPcGAzSHuYxwmE",
-            "DQQGPtj7pphPHCLzzBuEyDDQByUcKGrsJdsH7SP3hAug",
-            "3o6xgkJ9sTmDeQWyfj3sxwon18fXJB9PV5LDc8sfgR4a",
-            "Hm9JW7of5i9dnrboS8pCUCSeoQUPh7JsP1rkbJnW7An4",
-            "BhvLngiqqKeZ8rpxch2uGjeCiC88zzewoWPRuoxpp1aS",
-            "BuCEvc9ze8UoAQwwsQLy8d447C8sA4zeVtVpc6m5wQeS",
-            "GhsotwFMH6XUrRLJCxcx62h7748N2Uq8mf87hUGkmPhg",
-            "8UVjvYyoqP6sqcctTso3xpCdCfgTMiv3VRh7vraC2eJk",
-            "8DE8fqPfv1fp9DHyGyDFFaMjpopMgDeXspzoi9jpBJjC",
-            "HKJgYGTTYYR2ZkfJKHbn58w676fKueQXmvbtpyvrSM3N",
-            "3jnknRabs7G2V9dKhxd2KP85pNWXKXiedYnYxtySnQMs",
-            "Fgyh8EeYGZtbW8sS33YmNQnzx54WXPrJ5KWNPkCfWPot",
-            "5smrYwb1Hr2T8XMnvsqccTgXxuqQs14iuE8RbHFYf2Cf",
-            "6zw7em7uQdmMpuS9fGz8Nq9TLHa5YQhEKKwPjo5PwDK4",
-            "9hknftBZAQL4f48tWfk3bUEV5YSLcYYtDRqNmpNnhCWG",
-            "DUS1KxwUhUyDKB4A81E8vdnTe3hSahd92Abtn9CXsEcj",
-            "GLUmCeJpXB8veNcchPwibkRYwCwvQbKodex5mEjrgToi",
-            "EAJJD6nDqtXcZ4DnQb19F9XEz8y8bRDHxbWbahatZNbL",
-            "GpYnVDgB7dzvwSgsjQFeHznjG6Kt1DLBFYrKxjGU1LuD",
-            "CTvhdUVf8KNyMbyEdnvRrBCHJjBKtQwkbj6zwoqcEssG"
-          ],
-          "total": 503000508500862375
-        }
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getVoteAccounts",
-    "method": "getVoteAccounts",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "current": [
-          {
-            "activatedStake": 999999997717120,
-            "commission": 0,
-            "epochCredits": [
-              [
-                0,
-                144,
-                0
-              ]
-            ],
-            "epochVoteAccount": true,
-            "lastVote": 40,
-            "nodePubkey": "EWEDURnEjTRSa5Uz99Kf3hdThUD8X2Rv7RvMFLSQ1DCm",
-            "rootSlot": 9,
-            "votePubkey": "3nsvie2PSWMWitUgkKNzKqzaFEUhGahKW51HhR8ThqTc"
-          }
-        ],
-        "delinquent": []
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getMinimumBalanceForRentExemption",
-    "method": "getMinimumBalanceForRentExemption",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": 2039280,
-      "id": 1
-    },
-    "params": [
-      165
-    ]
-  },
-  {
-    "name": "getBalance",
-    "method": "getBalance",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": 8996474120
-      },
-      "id": 1
-    },
-    "params": [
-      "6o185vKXeS8D27dPfAKxJ2dNVD8iNjmRpFwdYYk3uSrT"
-    ]
-  },
-  {
-    "name": "getAccountInfo",
-    "method": "getAccountInfo",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": {
-          "data": [
-            "",
-            "base64"
-          ],
-          "executable": false,
-          "lamports": 8996474120,
-          "owner": "11111111111111111111111111111111",
-          "rentEpoch": 18446744073709551615,
-          "space": 0
-        }
-      },
-      "id": 1
-    },
-    "params": [
-      "6o185vKXeS8D27dPfAKxJ2dNVD8iNjmRpFwdYYk3uSrT",
-      {
-        "encoding": "base64"
-      }
-    ]
-  },
-  {
-    "name": "getAccountInfo-missing",
-    "method": "getAccountInfo",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": null
-      },
-      "id": 1
-    },
-    "params": [
-      "11111111111111111111111111111112",
-      {
-        "encoding": "base64"
-      }
-    ]
-  },
-  {
-    "name": "getMultipleAccounts",
-    "method": "getMultipleAccounts",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": [
-          {
-            "data": [
-              "",
-              "base64"
-            ],
-            "executable": false,
-            "lamports": 8996474120,
-            "owner": "11111111111111111111111111111111",
-            "rentEpoch": 18446744073709551615,
-            "space": 0
-          },
-          {
-            "data": [
-              "",
-              "base64"
-            ],
-            "executable": false,
-            "lamports": 1000000000,
-            "owner": "11111111111111111111111111111111",
-            "rentEpoch": 18446744073709551615,
-            "space": 0
-          }
-        ]
-      },
-      "id": 1
-    },
-    "params": [
-      [
-        "6o185vKXeS8D27dPfAKxJ2dNVD8iNjmRpFwdYYk3uSrT",
-        "HR7KwDBsCkkoe9VPCuZhtwgcJMUMLMgFJb6n9WuLqyop"
-      ],
-      {
-        "encoding": "base64"
-      }
-    ]
-  },
-  {
-    "name": "getLargestAccounts",
-    "method": "getLargestAccounts",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": [
-          {
-            "address": "594C9C199Zp8fK2zvmXrSveE359gijrM6tsoZLYk9obv",
-            "lamports": 500000000000000000
-          },
-          {
-            "address": "BxqNA9vLoWDNiEBzZ4na79hBvUUke2jfTXiki4sfr5J4",
-            "lamports": 1000000000000000
-          },
-          {
-            "address": "3nsvie2PSWMWitUgkKNzKqzaFEUhGahKW51HhR8ThqTc",
-            "lamports": 1000000000000000
-          },
-          {
-            "address": "D758ERd8UUz83zLzxG2ykpTGSWog3HFjST7Bu1nd3bPm",
-            "lamports": 999989999995000
-          },
-          {
-            "address": "EWEDURnEjTRSa5Uz99Kf3hdThUD8X2Rv7RvMFLSQ1DCm",
-            "lamports": 499999815000
-          },
-          {
-            "address": "6o185vKXeS8D27dPfAKxJ2dNVD8iNjmRpFwdYYk3uSrT",
-            "lamports": 8996474120
-          },
-          {
-            "address": "DoU57AYuPFu2QU514RktNPG22QhApEjnKxnBcu4BHDTY",
-            "lamports": 3773078640
-          },
-          {
-            "address": "HR7KwDBsCkkoe9VPCuZhtwgcJMUMLMgFJb6n9WuLqyop",
-            "lamports": 1000000000
-          },
-          {
-            "address": "So11111111111111111111111111111111111111112",
-            "lamports": 1000000000
-          },
-          {
-            "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
-            "lamports": 929020800
-          },
-          {
-            "address": "SysvarS1otHistory11111111111111111111111111",
-            "lamports": 913326000
-          },
-          {
-            "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
-            "lamports": 731913600
-          },
-          {
-            "address": "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr",
-            "lamports": 521498880
-          },
-          {
-            "address": "SysvarS1otHashes111111111111111111111111111",
-            "lamports": 143487360
-          },
-          {
-            "address": "Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo",
-            "lamports": 119712000
-          },
-          {
-            "address": "SysvarStakeHistory1111111111111111111111111",
-            "lamports": 114979200
-          },
-          {
-            "address": "SysvarRecentB1ockHashes11111111111111111111",
-            "lamports": 42706560
-          },
-          {
-            "address": "B2kGD5aSJLL8yHUUC8v7VWWyF6DRN6m2kpjhiPin53oe",
-            "lamports": 2039280
-          },
-          {
-            "address": "nsAeRzrkWAUJkGnTnnx1nhr3DokGui17CLUNuEwnoaw",
-            "lamports": 1461600
-          },
-          {
-            "address": "SysvarC1ock11111111111111111111111111111111",
-            "lamports": 1169280
-          }
-        ]
-      },
-      "id": 1
-    }
-  },
-  {
-    "name": "getProgramAccounts",
-    "method": "getProgramAccounts",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": [
-        {
-          "account": {
-            "data": [
-              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
-              "base64"
-            ],
-            "executable": false,
-            "lamports": 1000000000,
-            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
-            "rentEpoch": 1,
-            "space": 82
-          },
-          "pubkey": "So11111111111111111111111111111111111111112"
-        },
-        {
-          "account": {
-            "data": [
-              "AQAAAFYTSjtFgV37DhAKCpVZ7UaTRdOtkDEDLd/1PcZokXcYgN6AAgAAAAAGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
-              "base64"
-            ],
-            "executable": false,
-            "lamports": 1461600,
-            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
-            "rentEpoch": 18446744073709551615,
-            "space": 82
-          },
-          "pubkey": "nsAeRzrkWAUJkGnTnnx1nhr3DokGui17CLUNuEwnoaw"
-        },
-        {
-          "account": {
-            "data": [
-              "C7/cEE+JL6u+L/IR/d1bk+Y8tafJlr26pB6MKVNffjBWE0o7RYFd+w4QCgqVWe1Gk0XTrZAxAy3f9T3GaJF3GIDegAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
-              "base64"
-            ],
-            "executable": false,
-            "lamports": 2039280,
-            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
-            "rentEpoch": 18446744073709551615,
-            "space": 165
-          },
-          "pubkey": "B2kGD5aSJLL8yHUUC8v7VWWyF6DRN6m2kpjhiPin53oe"
-        }
-      ],
-      "id": 1
-    },
-    "params": [
-      "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
-      {
-        "encoding": "base64"
-      }
-    ]
-  },
-  {
-    "name": "getSignaturesForAddress",
-    "method": "getSignaturesForAddress",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": [
-        {
-          "blockTime": 1785728550,
-          "confirmationStatus": "finalized",
-          "err": null,
-          "memo": null,
-          "signature": "4xzhXw7xxNCGfC74NKbZNEcr92zWdGviq4GJbksRxdXz2NGYFh8Jzyox5X7trorYyYvKEnPHkfNsAfCQA5KAhFRC",
-          "slot": 5
-        }
-      ],
-      "id": 1
-    },
-    "params": [
-      "HR7KwDBsCkkoe9VPCuZhtwgcJMUMLMgFJb6n9WuLqyop",
-      {
-        "limit": 3
-      }
-    ]
-  },
-  {
-    "name": "getSignatureStatuses",
-    "method": "getSignatureStatuses",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 72
-        },
-        "value": [
-          {
-            "confirmationStatus": "finalized",
-            "confirmations": null,
-            "err": null,
-            "slot": 5,
-            "status": {
-              "Ok": null
-            }
-          }
-        ]
-      },
-      "id": 1
-    },
-    "params": [
-      [
-        "4xzhXw7xxNCGfC74NKbZNEcr92zWdGviq4GJbksRxdXz2NGYFh8Jzyox5X7trorYyYvKEnPHkfNsAfCQA5KAhFRC"
-      ],
-      {
-        "searchTransactionHistory": true
-      }
-    ]
-  },
-  {
-    "name": "getTransaction",
-    "method": "getTransaction",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "blockTime": 1785728550,
-        "meta": {
-          "computeUnitsConsumed": 150,
-          "err": null,
-          "fee": 5000,
-          "innerInstructions": [],
-          "loadedAddresses": {
-            "readonly": [],
-            "writable": []
-          },
-          "logMessages": [
-            "Program 11111111111111111111111111111111 invoke [1]",
-            "Program 11111111111111111111111111111111 success"
-          ],
-          "postBalances": [
-            8999995000,
-            1000000000,
-            1
-          ],
-          "postTokenBalances": [],
-          "preBalances": [
-            10000000000,
-            0,
-            1
-          ],
-          "preTokenBalances": [],
-          "rewards": [],
-          "status": {
-            "Ok": null
-          }
-        },
-        "slot": 5,
-        "transaction": {
-          "message": {
-            "accountKeys": [
-              "6o185vKXeS8D27dPfAKxJ2dNVD8iNjmRpFwdYYk3uSrT",
-              "HR7KwDBsCkkoe9VPCuZhtwgcJMUMLMgFJb6n9WuLqyop",
-              "11111111111111111111111111111111"
-            ],
-            "header": {
-              "numReadonlySignedAccounts": 0,
-              "numReadonlyUnsignedAccounts": 1,
-              "numRequiredSignatures": 1
-            },
-            "instructions": [
-              {
-                "accounts": [
-                  0,
-                  1
-                ],
-                "data": "3Bxs3zzLZLuLQEYX",
-                "programIdIndex": 2,
-                "stackHeight": null
-              }
-            ],
-            "recentBlockhash": "4phmBxWpU7uba3moNmwyDKbH1iADu4zsUUKHbXyVbqfx"
-          },
-          "signatures": [
-            "4xzhXw7xxNCGfC74NKbZNEcr92zWdGviq4GJbksRxdXz2NGYFh8Jzyox5X7trorYyYvKEnPHkfNsAfCQA5KAhFRC"
-          ]
-        },
-        "version": "legacy"
-      },
-      "id": 1
-    },
-    "params": [
-      "4xzhXw7xxNCGfC74NKbZNEcr92zWdGviq4GJbksRxdXz2NGYFh8Jzyox5X7trorYyYvKEnPHkfNsAfCQA5KAhFRC",
-      {
-        "encoding": "json",
-        "maxSupportedTransactionVersion": 0
-      }
-    ]
-  },
-  {
-    "name": "getTokenSupply",
-    "method": "getTokenSupply",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": {
-          "amount": "42000000",
-          "decimals": 6,
-          "uiAmount": 42.0,
-          "uiAmountString": "42"
-        }
-      },
-      "id": 1
-    },
-    "params": [
-      "nsAeRzrkWAUJkGnTnnx1nhr3DokGui17CLUNuEwnoaw"
-    ]
-  },
-  {
-    "name": "getTokenAccountBalance",
-    "method": "getTokenAccountBalance",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": {
-          "amount": "42000000",
-          "decimals": 6,
-          "uiAmount": 42.0,
-          "uiAmountString": "42"
-        }
-      },
-      "id": 1
-    },
-    "params": [
-      "B2kGD5aSJLL8yHUUC8v7VWWyF6DRN6m2kpjhiPin53oe"
-    ]
-  },
-  {
-    "name": "getTokenLargestAccounts",
-    "method": "getTokenLargestAccounts",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": [
-          {
-            "address": "B2kGD5aSJLL8yHUUC8v7VWWyF6DRN6m2kpjhiPin53oe",
-            "amount": "42000000",
-            "decimals": 6,
-            "uiAmount": 42.0,
-            "uiAmountString": "42"
-          }
-        ]
-      },
-      "id": 1
-    },
-    "params": [
-      "nsAeRzrkWAUJkGnTnnx1nhr3DokGui17CLUNuEwnoaw"
-    ]
-  },
-  {
-    "name": "getTokenAccountsByOwner",
-    "method": "getTokenAccountsByOwner",
-    "response": {
-      "jsonrpc": "2.0",
-      "result": {
-        "context": {
-          "apiVersion": "2.1.16",
-          "slot": 41
-        },
-        "value": [
-          {
-            "account": {
-              "data": [
-                "C7/cEE+JL6u+L/IR/d1bk+Y8tafJlr26pB6MKVNffjBWE0o7RYFd+w4QCgqVWe1Gk0XTrZAxAy3f9T3GaJF3GIDegAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
-                "base64"
-              ],
-              "executable": false,
-              "lamports": 2039280,
-              "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
-              "rentEpoch": 18446744073709551615,
-              "space": 165
-            },
-            "pubkey": "B2kGD5aSJLL8yHUUC8v7VWWyF6DRN6m2kpjhiPin53oe"
-          }
-        ]
-      },
-      "id": 1
-    },
-    "params": [
-      "6o185vKXeS8D27dPfAKxJ2dNVD8iNjmRpFwdYYk3uSrT",
-      {
-        "mint": "nsAeRzrkWAUJkGnTnnx1nhr3DokGui17CLUNuEwnoaw"
+        "identity": "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13"
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getClusterNodes",
+    "method": "getClusterNodes",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        {
+          "featureSet": 3271415109,
+          "gossip": "127.0.0.1:1024",
+          "pubkey": "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13",
+          "pubsub": "127.0.0.1:8900",
+          "rpc": "127.0.0.1:8899",
+          "serveRepair": "127.0.0.1:1035",
+          "shredVersion": 21032,
+          "tpu": "127.0.0.1:1027",
+          "tpuForwards": "127.0.0.1:1028",
+          "tpuForwardsQuic": "127.0.0.1:1034",
+          "tpuQuic": "127.0.0.1:1033",
+          "tpuVote": "127.0.0.1:1029",
+          "tvu": "127.0.0.1:1025",
+          "version": "2.1.16"
+        }
+      ],
+      "id": 1
+    }
+  },
+  {
+    "name": "getHealth",
+    "method": "getHealth",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": "ok",
+      "id": 1
+    }
+  },
+  {
+    "name": "getHighestSnapshotSlot",
+    "method": "getHighestSnapshotSlot",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "full": 1100,
+        "incremental": null
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getRecentPrioritizationFees",
+    "method": "getRecentPrioritizationFees",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        {
+          "prioritizationFee": 0,
+          "slot": 82
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 94
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 116
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 126
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 148
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 161
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 180
+        },
+        {
+          "prioritizationFee": 10000,
+          "slot": 193
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 212
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 228
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 244
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 260
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 277
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 293
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 309
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 341
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 373
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 375
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 378
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 380
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 382
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 414
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 446
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 478
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 511
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 545
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 577
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 610
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 644
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 646
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 648
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 680
+        },
+        {
+          "prioritizationFee": 1000,
+          "slot": 713
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 745
+        },
+        {
+          "prioritizationFee": 10000,
+          "slot": 777
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 809
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 842
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 844
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 881
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 914
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 946
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 978
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1010
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1138
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1139
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1141
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1143
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1176
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1177
+        }
+      ],
+      "id": 1
+    }
+  },
+  {
+    "name": "getRecentPrioritizationFees-filtered",
+    "method": "getRecentPrioritizationFees",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        {
+          "prioritizationFee": 0,
+          "slot": 82
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 94
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 116
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 126
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 148
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 161
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 180
+        },
+        {
+          "prioritizationFee": 10000,
+          "slot": 193
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 212
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 228
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 244
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 260
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 277
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 293
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 309
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 341
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 373
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 375
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 378
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 380
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 382
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 414
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 446
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 478
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 511
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 545
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 577
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 610
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 644
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 646
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 648
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 680
+        },
+        {
+          "prioritizationFee": 1000,
+          "slot": 713
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 745
+        },
+        {
+          "prioritizationFee": 10000,
+          "slot": 777
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 809
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 842
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 844
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 881
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 914
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 946
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 978
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1010
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1138
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1139
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1141
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1143
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1176
+        },
+        {
+          "prioritizationFee": 0,
+          "slot": 1177
+        }
+      ],
+      "id": 1
+    },
+    "params": [
+      [
+        "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU"
+      ]
+    ]
+  },
+  {
+    "name": "getEpochInfo",
+    "method": "getEpochInfo",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "absoluteSlot": 1179,
+        "blockHeight": 1179,
+        "epoch": 36,
+        "slotIndex": 27,
+        "slotsInEpoch": 32,
+        "transactionCount": 1229
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getEpochSchedule",
+    "method": "getEpochSchedule",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "firstNormalEpoch": 0,
+        "firstNormalSlot": 0,
+        "leaderScheduleSlotOffset": 32,
+        "slotsPerEpoch": 32,
+        "warmup": false
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getGenesisHash",
+    "method": "getGenesisHash",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": "AShwgvZDRwHrzE3fEfQaDVzuADQxmX2w2pWZzViPiLkr",
+      "id": 1
+    }
+  },
+  {
+    "name": "getSlot",
+    "method": "getSlot",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": 1179,
+      "id": 1
+    }
+  },
+  {
+    "name": "getBlockHeight",
+    "method": "getBlockHeight",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": 1179,
+      "id": 1
+    }
+  },
+  {
+    "name": "getTransactionCount",
+    "method": "getTransactionCount",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": 1229,
+      "id": 1
+    }
+  },
+  {
+    "name": "getFirstAvailableBlock",
+    "method": "getFirstAvailableBlock",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": 0,
+      "id": 1
+    }
+  },
+  {
+    "name": "getRecentPerformanceSamples",
+    "method": "getRecentPerformanceSamples",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        {
+          "numNonVoteTransactions": 1,
+          "numSlots": 129,
+          "numTransactions": 130,
+          "samplePeriodSecs": 60,
+          "slot": 1160
+        },
+        {
+          "numNonVoteTransactions": 4,
+          "numSlots": 128,
+          "numTransactions": 132,
+          "samplePeriodSecs": 60,
+          "slot": 1031
+        }
+      ],
+      "id": 1
+    },
+    "params": [
+      2
+    ]
+  },
+  {
+    "name": "getStakeMinimumDelegation",
+    "method": "getStakeMinimumDelegation",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": 1000000000
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getLeaderSchedule",
+    "method": "getLeaderSchedule",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13": [
+          0,
+          1,
+          2,
+          3,
+          4,
+          5,
+          6,
+          7,
+          8,
+          9,
+          10,
+          11,
+          12,
+          13,
+          14,
+          15,
+          16,
+          17,
+          18,
+          19,
+          20,
+          21,
+          22,
+          23,
+          24,
+          25,
+          26,
+          27,
+          28,
+          29,
+          30,
+          31
+        ]
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getSlotLeader",
+    "method": "getSlotLeader",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13",
+      "id": 1
+    }
+  },
+  {
+    "name": "getSlotLeaders",
+    "method": "getSlotLeaders",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13",
+        "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13",
+        "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13"
+      ],
+      "id": 1
+    },
+    "params": [
+      1139,
+      3
+    ]
+  },
+  {
+    "name": "getMaxRetransmitSlot",
+    "method": "getMaxRetransmitSlot",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": 0,
+      "id": 1
+    }
+  },
+  {
+    "name": "getMaxShredInsertSlot",
+    "method": "getMaxShredInsertSlot",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": 0,
+      "id": 1
+    }
+  },
+  {
+    "name": "minimumLedgerSlot",
+    "method": "minimumLedgerSlot",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": 0,
+      "id": 1
+    }
+  },
+  {
+    "name": "getLatestBlockhash",
+    "method": "getLatestBlockhash",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": {
+          "blockhash": "9T2jk2eWMKXFxfzXDikbSBZVTyoDT3jX8wanugptwD2C",
+          "lastValidBlockHeight": 1329
+        }
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "isBlockhashValid",
+    "method": "isBlockhashValid",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1210
+        },
+        "value": true
+      },
+      "id": 1
+    },
+    "params": [
+      "Dsw1cH6sgkBV86MjpDU7JiBzwxpu6aJuKBYZ2esXgV28",
+      {
+        "commitment": "processed"
+      }
+    ]
+  },
+  {
+    "name": "getBlock",
+    "method": "getBlock",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "blockHeight": 1139,
+        "blockTime": 1789304691,
+        "blockhash": "9ABjGUtGC2FDYzUDYyQvCZ9UyS7oTuXt66ur19zSFYeb",
+        "parentSlot": 1138,
+        "previousBlockhash": "GVHCpiV2HaJBYYxpxTvaA7sHiD9BKfmAc8zPQWUvz37C",
+        "transactions": [
+          {
+            "meta": {
+              "computeUnitsConsumed": 2100,
+              "err": null,
+              "fee": 10000,
+              "innerInstructions": [],
+              "loadedAddresses": {
+                "readonly": [],
+                "writable": []
+              },
+              "logMessages": [
+                "Program Vote111111111111111111111111111111111111111 invoke [1]",
+                "Program Vote111111111111111111111111111111111111111 success"
+              ],
+              "postBalances": [
+                499994441520,
+                1000000000000000,
+                1
+              ],
+              "postTokenBalances": [],
+              "preBalances": [
+                499994451520,
+                1000000000000000,
+                1
+              ],
+              "preTokenBalances": [],
+              "rewards": null,
+              "status": {
+                "Ok": null
+              }
+            },
+            "transaction": {
+              "message": {
+                "accountKeys": [
+                  "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13",
+                  "6PE42VjbVgozfFAEu8qMXQgvST4spCnw37FBfeYCrL16",
+                  "Vote111111111111111111111111111111111111111"
+                ],
+                "header": {
+                  "numReadonlySignedAccounts": 0,
+                  "numReadonlyUnsignedAccounts": 1,
+                  "numRequiredSignatures": 2
+                },
+                "instructions": [
+                  {
+                    "accounts": [
+                      1,
+                      1
+                    ],
+                    "data": "67MGn4nXadYkNgbgzrF38aJ9SAiTjzMaSDcDx5WSFsQSgrMCY3FtcxBw8sSJ6qUmiaAqsAUFVreXshpdo75uwtHcM3rtmfKGSRanHwDCrFjsVCXSVM9WqDcd2S7MxDj48mXXsid3DiBmSNxLjFSxeCLAMm84mNFRzzSxCgLTaGPp2o5XxZSX4TLc5svDhhJ5Wfy3YqBb8s",
+                    "programIdIndex": 2,
+                    "stackHeight": null
+                  }
+                ],
+                "recentBlockhash": "GVHCpiV2HaJBYYxpxTvaA7sHiD9BKfmAc8zPQWUvz37C"
+              },
+              "signatures": [
+                "256ZKFLjMhx4fK1NLCzZ7dUDgsbD3xhnLJeysfi9WKxjdNn473XT3piVWAeMxK1KWsFtYBY8NcvTYuCd5YeVio3K",
+                "3MVSryX7NdqzF2HHNqdWu9MVTfAWfjNyoDe2AhySGiTU5KXMEiUPZxZNh7bH4fhGQjmQsLn4Ym8qoV8fv7Y8yFec"
+              ]
+            },
+            "version": "legacy"
+          },
+          {
+            "meta": {
+              "computeUnitsConsumed": 150,
+              "err": null,
+              "fee": 5000,
+              "innerInstructions": [],
+              "loadedAddresses": {
+                "readonly": [],
+                "writable": []
+              },
+              "logMessages": [
+                "Program 11111111111111111111111111111111 invoke [1]",
+                "Program 11111111111111111111111111111111 success"
+              ],
+              "postBalances": [
+                8999995000,
+                1000000000,
+                1
+              ],
+              "postTokenBalances": [],
+              "preBalances": [
+                10000000000,
+                0,
+                1
+              ],
+              "preTokenBalances": [],
+              "rewards": null,
+              "status": {
+                "Ok": null
+              }
+            },
+            "transaction": {
+              "message": {
+                "accountKeys": [
+                  "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU",
+                  "7CJWFMwehUcFsPqFpxbCrcZM5QwzkvFyhqTyMvbLd57t",
+                  "11111111111111111111111111111111"
+                ],
+                "header": {
+                  "numReadonlySignedAccounts": 0,
+                  "numReadonlyUnsignedAccounts": 1,
+                  "numRequiredSignatures": 1
+                },
+                "instructions": [
+                  {
+                    "accounts": [
+                      0,
+                      1
+                    ],
+                    "data": "3Bxs3zzLZLuLQEYX",
+                    "programIdIndex": 2,
+                    "stackHeight": null
+                  }
+                ],
+                "recentBlockhash": "GVHCpiV2HaJBYYxpxTvaA7sHiD9BKfmAc8zPQWUvz37C"
+              },
+              "signatures": [
+                "7LWBsxy64WXiaaPRWic6Bz71xfN9mCrE9Ai54pHCRHjA1a6f454FFc1FaHafQV7VYvAtd35WpGB7b3CSLPkiimt"
+              ]
+            },
+            "version": "legacy"
+          }
+        ]
+      },
+      "id": 1
+    },
+    "params": [
+      1139,
+      {
+        "encoding": "json",
+        "maxSupportedTransactionVersion": 0,
+        "transactionDetails": "full",
+        "rewards": false
+      }
+    ]
+  },
+  {
+    "name": "getBlockCommitment",
+    "method": "getBlockCommitment",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "commitment": [
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          0,
+          1000558210106701
+        ],
+        "totalStake": 1000558210106701
+      },
+      "id": 1
+    },
+    "params": [
+      1139
+    ]
+  },
+  {
+    "name": "getBlockProduction",
+    "method": "getBlockProduction",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": {
+          "byIdentity": {
+            "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13": [
+              28,
+              28
+            ]
+          },
+          "range": {
+            "firstSlot": 1152,
+            "lastSlot": 1179
+          }
+        }
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getBlocks",
+    "method": "getBlocks",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        1137,
+        1138,
+        1139
+      ],
+      "id": 1
+    },
+    "params": [
+      1137,
+      1139
+    ]
+  },
+  {
+    "name": "getBlocksWithLimit",
+    "method": "getBlocksWithLimit",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        1137,
+        1138,
+        1139
+      ],
+      "id": 1
+    },
+    "params": [
+      1137,
+      3
+    ]
+  },
+  {
+    "name": "getBlockTime",
+    "method": "getBlockTime",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": 1789304691,
+      "id": 1
+    },
+    "params": [
+      1139
+    ]
+  },
+  {
+    "name": "getInflationGovernor",
+    "method": "getInflationGovernor",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "foundation": 0.05,
+        "foundationTerm": 7.0,
+        "initial": 0.08,
+        "taper": 0.15,
+        "terminal": 0.015
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getInflationRate",
+    "method": "getInflationRate",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "epoch": 36,
+        "foundation": 0.0039999905074868366,
+        "total": 0.07999981014973673,
+        "validator": 0.07599981964224989
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getInflationReward",
+    "method": "getInflationReward",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        {
+          "amount": 15505890732,
+          "commission": 0,
+          "effectiveSlot": 1153,
+          "epoch": 35,
+          "postBalance": 1000542706499393
+        }
+      ],
+      "id": 1
+    },
+    "params": [
+      [
+        "ADdiFqTcHJQS8ay9LJqXRcBArpetNszyJcUyoqWL43ge"
+      ]
+    ]
+  },
+  {
+    "name": "getSupply",
+    "method": "getSupply",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": {
+          "circulating": 503001051202993908,
+          "nonCirculating": 0,
+          "nonCirculatingAccounts": [
+            "HuqDWJodFhAEWh6aWdsDVUqsjRket5DYXMYyDYtD8hdN",
+            "GEWSkfWgHkpiLbeKaAnwvqnECGdRNf49at5nFccVey7c",
+            "Dc2oHxFXQaC2QfLStuU7txtD3U5HZ82MrCSGDooWjbsv",
+            "HQJtLqvEGGxgNYfRXUurfxV8E1swvCnsbC3456ik27HY",
+            "DE1bawNcRJB9rVm3buyMVfr8mBEoyyu73NBovf2oXJsJ",
+            "FiWYY85b58zEEcPtxe3PuqzWPjqBJXqdwgZeqSBmT9Cn",
+            "Fg12tB1tz8w6zJSQ4ZAGotWoCztdMJF9hqK8R11pakog",
+            "BUnRE27mYXN9p8H1Ay24GXhJC88q2CuwLoNU2v2CrW4W",
+            "4sxwau4mdqZ8zEJsfryXq4QFYnMJSCp3HWuZQod8WU5k",
+            "9huDUZfxoJ7wGMTffUE7vh1xePqef7gyrLJu9NApncqA",
+            "Eyr9P5XsjK2NUKNCnfu39eqpGoiLFgVAv1LSQgMZCwiQ",
+            "8ndGYFjav6NDXvzYcxs449Aub3AxYv4vYpk89zRDwgj7",
+            "3jnknRabs7G2V9dKhxd2KP85pNWXKXiedYnYxtySnQMs",
+            "AG3m2bAibcY8raMt4oXEGqRHwX4FWKPPJVjZxn1LySDX",
+            "5XdtyEDREHJXXW1CTtCsVjJRjBapAwK78ZquzvnNVRrV",
+            "7Y8smnoUrYKGGuDq2uaFKVxJYhojgg7DVixHyAtGTYEV",
+            "7cvkjYAkUYs4W8XcXsca7cBrEGFeSUjeZmKoNBvEwyri",
+            "CzAHrrrHKx9Lxf6wdCMrsZkLvk74c7J2vGv8VYPUmY6v",
+            "8CUUMKYNGxdgYio5CLHRHyzMEhhVRMcqefgE6dLqnVRK",
+            "CHmdL15akDcJgBkY6BP3hzs98Dqr6wbdDC5p8odvtSbq",
+            "6yKHERk8rsbmJxvMpPuwPs1ct3hRiP7xaJF2tvnGU6nK",
+            "CUageMFi49kzoDqtdU8NvQ4Bq3sbtJygjKDAXJ45nmAi",
+            "HbZ5FfmKWNHC7uwk6TF1hVi6TCs7dtYfdjEcuPGgzFAg",
+            "5smrYwb1Hr2T8XMnvsqccTgXxuqQs14iuE8RbHFYf2Cf",
+            "7xJ9CLtEAcEShw9kW2gSoZkRWL566Dg12cvgzANJwbTr",
+            "2WWb1gRzuXDd5viZLQF7pNRR6Y7UiyeaPpaL35X6j3ve",
+            "DQQGPtj7pphPHCLzzBuEyDDQByUcKGrsJdsH7SP3hAug",
+            "6o5v1HC7WhBnLfRHp8mQTtCP2khdXXjhuyGyYEoy2Suy",
+            "FwfaykN7ACnsEUDHANzGHqTGQZMcGnUSsahAHUqbdPrz",
+            "Ep5Y58PaSyALPrdFxDVAdfKtVdP55vApvsWjb3jSmXsG",
+            "AzHQ8Bia1grVVbcGyci7wzueSWkgvu7YZVZ4B9rkL5P6",
+            "BhvLngiqqKeZ8rpxch2uGjeCiC88zzewoWPRuoxpp1aS",
+            "5khMKAcvmsFaAhoKkdg3u5abvKsmjUQNmhTNP624WB1F",
+            "FR84wZQy3Y3j2gWz6pgETUiUoJtreMEuWfbg6573UCj9",
+            "HCV5dGFJXRrJ3jhDYA4DCeb9TEDTwGGYXtT3wHksu2Zr",
+            "JCwT5Ygmq3VeBEbDjL8s8E82Ra2rP9bq45QfZE7Xyaq7",
+            "63DtkW7zuARcd185EmHAkfF44bDcC2SiTSEj2spLP3iA",
+            "CuatS6njAcfkFHnvai7zXCs7syA9bykXWsDCJEWfhjHG",
+            "6nN69B4uZuESZYxr9nrLDjmKRtjDZQXrehwkfQTKw62U",
+            "EMhn1U3TMimW3bvWYbPUvN2eZnCfsuBN4LGWhzzYhiWR",
+            "BsKsunvENxAraBrL77UfAn1Gi7unVEmQAdCbhsjUN6tU",
+            "3iPvAS4xdhYr6SkhVDHCLr7tJjMAFK4wvvHWJxFQVg15",
+            "5PLJZLJiRR9vf7d1JCCg7UuWjtyN9nkab9uok6TqSyuP",
+            "CQDYc4ET2mbFhVpgj41gXahL6Exn5ZoPcGAzSHuYxwmE",
+            "CWeRmXme7LmbaUWTZWFLt6FMnpzLCHaQLuR2TdgFn4Lq",
+            "CakcnaRDHka2gXyfbEd2d3xsvkJkqsLw2akB3zsN1D2S",
+            "BUjkdqUuH5Lz9XzcMcR4DdEMnFG6r8QzUMBm16Rfau96",
+            "E8jcgWvrvV7rwYHJThwfiBeQ8VAH4FgNEEMG9aAuCMAq",
+            "CY7X5o3Wi2eQhTocLmUS6JSWyx1NinBfW7AXRrkRCpi8",
+            "5D5NxsNVTgXHyVziwV7mDFwVDS6voaBsyyGxUbhQrhNW",
+            "8pNBEppa1VcFAsx4Hzq9CpdXUXZjUXbvQwLX2K7QsCwb",
+            "EMAY24PrS6rWfvpqffFCsTsFJypeeYYmtUc26wdh3Wup",
+            "GK8R4uUmrawcREZ5xJy5dAzVV5V7aFvYg77id37pVTK",
+            "3itU5ME8L6FDqtMiRoUiT1F7PwbkTtHBbW51YWD5jtjm",
+            "6zw7em7uQdmMpuS9fGz8Nq9TLHa5YQhEKKwPjo5PwDK4",
+            "Es13uD2p64UVPFpEWfDtd6SERdoNR2XVgqBQBZcZSLqW",
+            "HUAkU5psJXZuw54Lrg1ksbXzHv2fzczQ9sNbmisVMeJU",
+            "3bTGcGB9F98XxnrBNftmmm48JGfPgi5sYxDEKiCjQYk3",
+            "BuCEvc9ze8UoAQwwsQLy8d447C8sA4zeVtVpc6m5wQeS",
+            "8DE8fqPfv1fp9DHyGyDFFaMjpopMgDeXspzoi9jpBJjC",
+            "7Np41oeYqPefeNQEHSv1UDhYrehxin3NStELsSKCT4K2",
+            "Fgyh8EeYGZtbW8sS33YmNQnzx54WXPrJ5KWNPkCfWPot",
+            "CTvhdUVf8KNyMbyEdnvRrBCHJjBKtQwkbj6zwoqcEssG",
+            "8rT45mqpuDBR1vcnDc9kwP9DrZAXDR4ZeuKWw3u1gTGa",
+            "4vuWt1oHRqLMhf8Nv1zyEXZsYaeK7dipwrfKLoYU9Riq",
+            "xQadXQiUTCCFhfHjvQx1hyJK6KVWr1w2fD6DT3cdwj7",
+            "GumSE5HsMV5HCwBTv2D2D81yy9x17aDkvobkqAfTRgmo",
+            "EAJJD6nDqtXcZ4DnQb19F9XEz8y8bRDHxbWbahatZNbL",
+            "AVYpwVou2BhdLivAwLxKPALZQsY7aZNkNmGbP2fZw7RU",
+            "GLUmCeJpXB8veNcchPwibkRYwCwvQbKodex5mEjrgToi",
+            "9hknftBZAQL4f48tWfk3bUEV5YSLcYYtDRqNmpNnhCWG",
+            "3o6xgkJ9sTmDeQWyfj3sxwon18fXJB9PV5LDc8sfgR4a",
+            "9S2M3UYPpnPZTBtbcUvehYmiWFK3kBhwfzV2iWuwvaVy",
+            "4pV47TiPzZ7SSBPHmgUvSLmH9mMSe8tjyPhQZGbi1zPC",
+            "AzVV9ZZDxTgW4wWfJmsG6ytaHpQGSe1yz76Nyy84VbQF",
+            "14FUT96s9swbmH7ZjpDvfEDywnAYy9zaNhv4xvezySGu",
+            "GmyW1nqYcrw7P7JqrcyP9ivU9hYNbrgZ1r5SYJJH41Fs",
+            "9xbcBZoGYFnfJZe81EDuDYKUm8xGkjzW8z4EgnVhNvsv",
+            "CsUqV42gVQLJwQsKyjWHqGkfHarxn9hcY4YeSjgaaeTd",
+            "H1rt8KvXkNhQExTRfkY8r9wjZbZ8yCih6J4wQ5Fz9HGP",
+            "Hm9JW7of5i9dnrboS8pCUCSeoQUPh7JsP1rkbJnW7An4",
+            "HKJgYGTTYYR2ZkfJKHbn58w676fKueQXmvbtpyvrSM3N",
+            "GNiz4Mq886bTNDT3pijGsu2gbw6it7sqrwncro45USeB",
+            "GK2zqSsXLA2rwVZk347RYhh6jJpRsCA69FjLW93ZGi3B",
+            "GpxpMVhrBBBEYbEJxdR62w3daWz444V7m6dxYDZKH77D",
+            "8UVjvYyoqP6sqcctTso3xpCdCfgTMiv3VRh7vraC2eJk",
+            "3ZrsTmNM6AkMcqFfv3ryfhQ2jMfqP64RQbqVyAaxqhrQ",
+            "Br3aeVGapRb2xTq17RU2pYZCoJpWA7bq6TKBCcYtMSmt",
+            "DrKzW5koKSZp4mg4BdHLwr72MMXscd2kTiWgckCvvPXz",
+            "Mc5XB47H3DKJHym5RLa9mPzWv5snERsF3KNv5AauXK8",
+            "3fV2GaDKa3pZxyDcpMh5Vrh2FVAMUiWUKbYmnBFv8As3",
+            "F9MWFw8cnYVwsRq8Am1PGfFL3cQUZV37mbGoxZftzLjN",
+            "GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ",
+            "DUS1KxwUhUyDKB4A81E8vdnTe3hSahd92Abtn9CXsEcj",
+            "EziVYi3Sv5kJWxmU77PnbrT8jmkVuqwdiFLLzZpLVEn7",
+            "GvpCiTgq9dmEeojCDBivoLoZqc4AkbUDACpqPMwYLWKh",
+            "CND6ZjRTzaCFVdX7pSSWgjTfHZuhxqFDoUBqWBJguNoA",
+            "P8aKfWQPeRnsZtpBrwWTYzyAoRk74KMz56xc6NEpC4J",
+            "Ab1UcdsFXZVnkSt1Z3vcYU65GQk5MvCbs54SviaiaqHb",
+            "GhsotwFMH6XUrRLJCxcx62h7748N2Uq8mf87hUGkmPhg",
+            "nGME7HgBT6tAJN1f6YuCCngpqT5cvSTndZUVLjQ4jwA",
+            "8vqrX3H2BYLaXVintse3gorPEM4TgTwTFZNN1Fm9TdYs",
+            "C7C8odR8oashR5Feyrq2tJKaXL18id1dSj2zbkDGL2C2",
+            "AsrYX4FeLXnZcrjcZmrASY2Eq1jvEeQfwxtNTxS5zojA",
+            "8W58E8JVJjH1jCy5CeHJQgvwFXTyAVyesuXRZGbcSUGG",
+            "H3Ni7vG1CsmJZdTvxF7RkAf9UM5qk4RsohJsmPvtZNnu",
+            "CVgyXrbEd1ctEuvq11QdpnCQVnPit8NLdhyqXQHLprM2",
+            "Hz9nydgN1k15wnwffKX7CSmZp4VFTnTwLXAEdomFGNXy",
+            "5q54XjQ7vDx4y6KphPeE97LUNiYGtP55spjvXAWPGBuf",
+            "GpYnVDgB7dzvwSgsjQFeHznjG6Kt1DLBFYrKxjGU1LuD"
+          ],
+          "total": 503001051202993908
+        }
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getVoteAccounts",
+    "method": "getVoteAccounts",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "current": [
+          {
+            "activatedStake": 1000542704216513,
+            "commission": 0,
+            "epochCredits": [
+              [
+                32,
+                16368,
+                15856
+              ],
+              [
+                33,
+                16880,
+                16368
+              ],
+              [
+                34,
+                17392,
+                16880
+              ],
+              [
+                35,
+                17904,
+                17392
+              ],
+              [
+                36,
+                18352,
+                17904
+              ]
+            ],
+            "epochVoteAccount": true,
+            "lastVote": 1178,
+            "nodePubkey": "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13",
+            "rootSlot": 1147,
+            "votePubkey": "6PE42VjbVgozfFAEu8qMXQgvST4spCnw37FBfeYCrL16"
+          }
+        ],
+        "delinquent": []
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getMinimumBalanceForRentExemption",
+    "method": "getMinimumBalanceForRentExemption",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": 2039280,
+      "id": 1
+    },
+    "params": [
+      165
+    ]
+  },
+  {
+    "name": "getBalance",
+    "method": "getBalance",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": 8996469120
+      },
+      "id": 1
+    },
+    "params": [
+      "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU"
+    ]
+  },
+  {
+    "name": "getAccountInfo",
+    "method": "getAccountInfo",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": {
+          "data": [
+            "",
+            "base64"
+          ],
+          "executable": false,
+          "lamports": 8996469120,
+          "owner": "11111111111111111111111111111111",
+          "rentEpoch": 18446744073709551615,
+          "space": 0
+        }
+      },
+      "id": 1
+    },
+    "params": [
+      "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU",
+      {
+        "encoding": "base64"
+      }
+    ]
+  },
+  {
+    "name": "getAccountInfo-missing",
+    "method": "getAccountInfo",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": null
+      },
+      "id": 1
+    },
+    "params": [
+      "11111111111111111111111111111112",
+      {
+        "encoding": "base64"
+      }
+    ]
+  },
+  {
+    "name": "getAccountInfo-base58",
+    "method": "getAccountInfo",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": {
+          "data": "DK9N3QzkXWLeDqMwkqAigERVBaD8rZUH5ajoRw1T243TXP5qCRvVNyytYSh3MBnhZ5GhBHo9PwRrMMyuUzCwZLMDTp9CBkrfRMxhwhVtQSKeXqZ",
+          "executable": false,
+          "lamports": 1461600,
+          "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+          "rentEpoch": 18446744073709551615,
+          "space": 82
+        }
+      },
+      "id": 1
+    },
+    "params": [
+      "GLHHB8i4NhGbp5KvPkSb9sWwW5W2M9ExHhFGooF3qjrZ"
+    ]
+  },
+  {
+    "name": "getAccountInfo-jsonParsed",
+    "method": "getAccountInfo",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": {
+          "data": {
+            "parsed": {
+              "info": {
+                "delegate": "7CJWFMwehUcFsPqFpxbCrcZM5QwzkvFyhqTyMvbLd57t",
+                "delegatedAmount": {
+                  "amount": "1000000",
+                  "decimals": 6,
+                  "uiAmount": 1.0,
+                  "uiAmountString": "1"
+                },
+                "isNative": false,
+                "mint": "GLHHB8i4NhGbp5KvPkSb9sWwW5W2M9ExHhFGooF3qjrZ",
+                "owner": "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU",
+                "state": "initialized",
+                "tokenAmount": {
+                  "amount": "42000000",
+                  "decimals": 6,
+                  "uiAmount": 42.0,
+                  "uiAmountString": "42"
+                }
+              },
+              "type": "account"
+            },
+            "program": "spl-token",
+            "space": 165
+          },
+          "executable": false,
+          "lamports": 2039280,
+          "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+          "rentEpoch": 18446744073709551615,
+          "space": 165
+        }
+      },
+      "id": 1
+    },
+    "params": [
+      "DsZB2RSj7Ry9e69QzCAbg7oFhAUuNYzzFkPbhXSSGTBX",
+      {
+        "encoding": "jsonParsed"
+      }
+    ]
+  },
+  {
+    "name": "getAccountInfo-jsonParsed-fallback",
+    "method": "getAccountInfo",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": {
+          "data": [
+            "",
+            "base64"
+          ],
+          "executable": false,
+          "lamports": 8996469120,
+          "owner": "11111111111111111111111111111111",
+          "rentEpoch": 18446744073709551615,
+          "space": 0
+        }
+      },
+      "id": 1
+    },
+    "params": [
+      "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU",
+      {
+        "encoding": "jsonParsed"
+      }
+    ]
+  },
+  {
+    "name": "getMultipleAccounts",
+    "method": "getMultipleAccounts",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": [
+          {
+            "data": [
+              "",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 8996469120,
+            "owner": "11111111111111111111111111111111",
+            "rentEpoch": 18446744073709551615,
+            "space": 0
+          },
+          {
+            "data": [
+              "",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 1000000000,
+            "owner": "11111111111111111111111111111111",
+            "rentEpoch": 18446744073709551615,
+            "space": 0
+          }
+        ]
+      },
+      "id": 1
+    },
+    "params": [
+      [
+        "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU",
+        "7CJWFMwehUcFsPqFpxbCrcZM5QwzkvFyhqTyMvbLd57t"
+      ],
+      {
+        "encoding": "base64"
+      }
+    ]
+  },
+  {
+    "name": "getLargestAccounts",
+    "method": "getLargestAccounts",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": [
+          {
+            "address": "594C9C199Zp8fK2zvmXrSveE359gijrM6tsoZLYk9obv",
+            "lamports": 500000000000000000
+          },
+          {
+            "address": "ADdiFqTcHJQS8ay9LJqXRcBArpetNszyJcUyoqWL43ge",
+            "lamports": 1000542706499393
+          },
+          {
+            "address": "6PE42VjbVgozfFAEu8qMXQgvST4spCnw37FBfeYCrL16",
+            "lamports": 1000000000000000
+          },
+          {
+            "address": "9WdyMYjoCgNpLUrYDHLtfMM5grfNrtRfWUAwRGe95gHj",
+            "lamports": 999930999905000
+          },
+          {
+            "address": "8XmVUUfAbS6kPE9EYK3Pt9JbitW1LYcez4GaEwJhWy13",
+            "lamports": 499994261520
+          },
+          {
+            "address": "9ZugqNkqmCZFqwwBV2L4axN2G3gHrrkhHA7z4aYBkAED",
+            "lamports": 9994444840
+          },
+          {
+            "address": "5XbxkDKu1Pig2pL422Ah2ccKTCetsx41KE5aFsSVUXZC",
+            "lamports": 8999995000
+          },
+          {
+            "address": "Dn6sL2FccobRZU21p8oXDZa4tUwEcb2ocCkhtyxqkZPt",
+            "lamports": 8999993000
+          },
+          {
+            "address": "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU",
+            "lamports": 8996469120
+          },
+          {
+            "address": "DoU57AYuPFu2QU514RktNPG22QhApEjnKxnBcu4BHDTY",
+            "lamports": 3773078640
+          },
+          {
+            "address": "9NZMSPPqaYtM45wGhC2P1UGzpmpr9Txf1YrG67XoEEH4",
+            "lamports": 2994444840
+          },
+          {
+            "address": "GHVKVku7jKWF9Wm1vm783JNMo1a7vcFjfjP53ox2kjHq",
+            "lamports": 2994429840
+          },
+          {
+            "address": "GpvMHGGKjpXvpEps5ojrQd9PcoexvBrEuoHgZa926svq",
+            "lamports": 2798258920
+          },
+          {
+            "address": "A988FuUtUVk8jMUuVc1ccaoTA3VS9CB4dkEf9XUAUqV4",
+            "lamports": 2000000000
+          },
+          {
+            "address": "AjHJq8a2rAvpEwPpCwmHSCXm9VNn2rsoGXUSzCueBYsz",
+            "lamports": 1999990000
+          },
+          {
+            "address": "5GrkvsgBcLbdwcVimm2WfHDmRxS6AqvDWoaX4UDTCBBa",
+            "lamports": 1999990000
+          },
+          {
+            "address": "3DpdBHnNFepEUJTiGrX6GiUUzRQ6GM6VKEHqXgSCV5sz",
+            "lamports": 1898537320
+          },
+          {
+            "address": "7ggMA8j7sCgoLTgaa7xSsbSaKvPPT6A614vaQHb6qUa",
+            "lamports": 1798532320
+          },
+          {
+            "address": "2VBTd7S7aEbZxc3m28s1h5HArw23m3Z4dQVFjXCW95Us",
+            "lamports": 1699994980
+          },
+          {
+            "address": "3PHvKBPpTRd7kiQ5DZKr4RPZJ7NubTTUuq3ksV1b1mYv",
+            "lamports": 1599995000
+          }
+        ]
+      },
+      "id": 1
+    }
+  },
+  {
+    "name": "getProgramAccounts",
+    "method": "getProgramAccounts",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        {
+          "account": {
+            "data": [
+              "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 1000000000,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 82
+          },
+          "pubkey": "So11111111111111111111111111111111111111112"
+        },
+        {
+          "account": {
+            "data": [
+              "f8yB2ezHuSXFgQc9OD5mrJG6yyEdcHOY3W05yMNPeq5/S6eJ+rOjhhlinyaXuJ2wREBn+uyvXRlFifoiZv7FukBUiQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 2039280,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 165
+          },
+          "pubkey": "nvrNy8RfWcWNd1Hk6UuVZpXKT4DcRH6RJwkkWVtZ2o5"
+        },
+        {
+          "account": {
+            "data": [
+              "0yYZmkq3kUcUc0zQu6kC8BsygDW6RwjWNkL9SAt/w0A3Z0QZx+w/ZzX78fBDdSj1HQeH0Brvpf+rTq49QT3UW0BCDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 2039280,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 165
+          },
+          "pubkey": "3DZ9VmQKPueP2woSUfKK9uXqnBpBvRP7o7tn4HHFdzKh"
+        },
+        {
+          "account": {
+            "data": [
+              "f8yB2ezHuSXFgQc9OD5mrJG6yyEdcHOY3W05yMNPeq6HzeKdDxux9wMt4eRrjxpvtFa/1y2QS6tYOd8YjYTgQ0BCDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 2039280,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 165
+          },
+          "pubkey": "3j5nSERqS4hghMmJZKzrKqPF4LRALodfR3ZZhWjesWwS"
+        },
+        {
+          "account": {
+            "data": [
+              "AQAAAOMYnftCUoqgz0EA+OL0ou/3PvWB9DEfOZyMqZ+s1A9gQEIPAAAAAAAGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 1461600,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 82
+          },
+          "pubkey": "5JrGPYnmLUQLP4r5itPc2BHL75SdJCDE5yyP99YZ39Zz"
+        },
+        {
+          "account": {
+            "data": [
+              "QAFTcLSa52Kdj963SMxdpWKdTgzfY2lloOGkvDtroUnjGJ37QlKKoM9BAPji9KLv9z71gfQxHzmcjKmfrNQPYLBxCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 2039280,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 165
+          },
+          "pubkey": "5SyXMRLKqg6fZW44kY5Tj1S6da1hd3iWHnj7ZVZoX6r1"
+        },
+        {
+          "account": {
+            "data": [
+              "0yYZmkq3kUcUc0zQu6kC8BsygDW6RwjWNkL9SAt/w0B8Y0X6Fnbib71unPZy51atANzZdq2s3zAa0I0RTeHjH0BUiQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 2039280,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 165
+          },
+          "pubkey": "6fR7HMCWnRvvrRFXFMYjnBNpXEoE2sJ5gS6n6jzZPryu"
+        },
+        {
+          "account": {
+            "data": [
+              "AQAAAH9Lp4n6s6OGGWKfJpe4nbBEQGf67K9dGUWJ+iJm/sW6gJaYAAAAAAAGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 1461600,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 82
+          },
+          "pubkey": "9bseQGaMu7zxy5ecFYBQCkS5R7LKufZg2r17NXNb1o9f"
+        },
+        {
+          "account": {
+            "data": [
+              "QAFTcLSa52Kdj963SMxdpWKdTgzfY2lloOGkvDtroUk/TVuRlPUmP/2lE0FZ2+oGYoIvlX4TJc2Tha7rd54025DQAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 2039280,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 165
+          },
+          "pubkey": "9rDLHt7wMAmAumaAs7C7ssyBuEYGPAjfqwVScjLV1imY"
+        },
+        {
+          "account": {
+            "data": [
+              "48++7/3R0WIonJxD1BvrGy92zcSxFsK3EIlKgUiPsQKABUnlbzpEmD/B9Mne0UtewK8vglXadt4+j5gxsciGXYDegAIAAAAAAQAAAFwLTXcQ1RvynIymV4tqc6oCAPQkAOGMo+Zz71Y4tzRvAQAAAAAAAAAAAAAAAEBCDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 2039280,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 165
+          },
+          "pubkey": "DsZB2RSj7Ry9e69QzCAbg7oFhAUuNYzzFkPbhXSSGTBX"
+        },
+        {
+          "account": {
+            "data": [
+              "AQAAAHxjRfoWduJvvW6c9nLnVq0A3Nl2razfMBrQjRFN4eMfgJaYAAAAAAAGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 1461600,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 82
+          },
+          "pubkey": "FDEimKKSp1YzmFnTSnj4NMRqqEuP8DW4QtTTphSWJk3h"
+        },
+        {
+          "account": {
+            "data": [
+              "AQAAAIAFSeVvOkSYP8H0yd7RS17Ary+CVdp23j6PmDGxyIZdgN6AAgAAAAAGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
+              "base64"
+            ],
+            "executable": false,
+            "lamports": 1461600,
+            "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+            "rentEpoch": 18446744073709551615,
+            "space": 82
+          },
+          "pubkey": "GLHHB8i4NhGbp5KvPkSb9sWwW5W2M9ExHhFGooF3qjrZ"
+        }
+      ],
+      "id": 1
+    },
+    "params": [
+      "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+      {
+        "encoding": "base64"
+      }
+    ]
+  },
+  {
+    "name": "getSignaturesForAddress",
+    "method": "getSignaturesForAddress",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": [
+        {
+          "blockTime": 1789304708,
+          "confirmationStatus": "finalized",
+          "err": null,
+          "memo": null,
+          "signature": "3C4AHsfWkBC2uWHop2ojYDph6xMYd4VjUEZFa1HToxYc216i9N9NoTPkKS4gPENnBoo4qdSXkUCEce99EMdXjqHx",
+          "slot": 1177
+        },
+        {
+          "blockTime": 1789304691,
+          "confirmationStatus": "finalized",
+          "err": null,
+          "memo": null,
+          "signature": "7LWBsxy64WXiaaPRWic6Bz71xfN9mCrE9Ai54pHCRHjA1a6f454FFc1FaHafQV7VYvAtd35WpGB7b3CSLPkiimt",
+          "slot": 1139
+        }
+      ],
+      "id": 1
+    },
+    "params": [
+      "7CJWFMwehUcFsPqFpxbCrcZM5QwzkvFyhqTyMvbLd57t",
+      {
+        "limit": 3
+      }
+    ]
+  },
+  {
+    "name": "getSignatureStatuses",
+    "method": "getSignatureStatuses",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1210
+        },
+        "value": [
+          {
+            "confirmationStatus": "finalized",
+            "confirmations": null,
+            "err": null,
+            "slot": 1139,
+            "status": {
+              "Ok": null
+            }
+          }
+        ]
+      },
+      "id": 1
+    },
+    "params": [
+      [
+        "7LWBsxy64WXiaaPRWic6Bz71xfN9mCrE9Ai54pHCRHjA1a6f454FFc1FaHafQV7VYvAtd35WpGB7b3CSLPkiimt"
+      ],
+      {
+        "searchTransactionHistory": true
+      }
+    ]
+  },
+  {
+    "name": "getTransaction",
+    "method": "getTransaction",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "blockTime": 1789304691,
+        "meta": {
+          "computeUnitsConsumed": 150,
+          "err": null,
+          "fee": 5000,
+          "innerInstructions": [],
+          "loadedAddresses": {
+            "readonly": [],
+            "writable": []
+          },
+          "logMessages": [
+            "Program 11111111111111111111111111111111 invoke [1]",
+            "Program 11111111111111111111111111111111 success"
+          ],
+          "postBalances": [
+            8999995000,
+            1000000000,
+            1
+          ],
+          "postTokenBalances": [],
+          "preBalances": [
+            10000000000,
+            0,
+            1
+          ],
+          "preTokenBalances": [],
+          "rewards": [],
+          "status": {
+            "Ok": null
+          }
+        },
+        "slot": 1139,
+        "transaction": {
+          "message": {
+            "accountKeys": [
+              "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU",
+              "7CJWFMwehUcFsPqFpxbCrcZM5QwzkvFyhqTyMvbLd57t",
+              "11111111111111111111111111111111"
+            ],
+            "header": {
+              "numReadonlySignedAccounts": 0,
+              "numReadonlyUnsignedAccounts": 1,
+              "numRequiredSignatures": 1
+            },
+            "instructions": [
+              {
+                "accounts": [
+                  0,
+                  1
+                ],
+                "data": "3Bxs3zzLZLuLQEYX",
+                "programIdIndex": 2,
+                "stackHeight": null
+              }
+            ],
+            "recentBlockhash": "GVHCpiV2HaJBYYxpxTvaA7sHiD9BKfmAc8zPQWUvz37C"
+          },
+          "signatures": [
+            "7LWBsxy64WXiaaPRWic6Bz71xfN9mCrE9Ai54pHCRHjA1a6f454FFc1FaHafQV7VYvAtd35WpGB7b3CSLPkiimt"
+          ]
+        },
+        "version": "legacy"
+      },
+      "id": 1
+    },
+    "params": [
+      "7LWBsxy64WXiaaPRWic6Bz71xfN9mCrE9Ai54pHCRHjA1a6f454FFc1FaHafQV7VYvAtd35WpGB7b3CSLPkiimt",
+      {
+        "encoding": "json",
+        "maxSupportedTransactionVersion": 0
+      }
+    ]
+  },
+  {
+    "name": "getFeeForMessage",
+    "method": "getFeeForMessage",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1210
+        },
+        "value": 5000
+      },
+      "id": 1
+    },
+    "params": [
+      "AQABA4AFSeVvOkSYP8H0yd7RS17Ary+CVdp23j6PmDGxyIZdXAtNdxDVG/KcjKZXi2pzqgIA9CQA4Yyj5nPvVji3NG8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL9YWnne+HJfKGpooSWeyzKzvXknewkQk0D2V2wXmj0pAQICAAEMAgAAAEBCDwAAAAAA",
+      {
+        "commitment": "processed"
+      }
+    ]
+  },
+  {
+    "name": "getTokenSupply",
+    "method": "getTokenSupply",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": {
+          "amount": "42000000",
+          "decimals": 6,
+          "uiAmount": 42.0,
+          "uiAmountString": "42"
+        }
+      },
+      "id": 1
+    },
+    "params": [
+      "GLHHB8i4NhGbp5KvPkSb9sWwW5W2M9ExHhFGooF3qjrZ"
+    ]
+  },
+  {
+    "name": "getTokenAccountBalance",
+    "method": "getTokenAccountBalance",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": {
+          "amount": "42000000",
+          "decimals": 6,
+          "uiAmount": 42.0,
+          "uiAmountString": "42"
+        }
+      },
+      "id": 1
+    },
+    "params": [
+      "DsZB2RSj7Ry9e69QzCAbg7oFhAUuNYzzFkPbhXSSGTBX"
+    ]
+  },
+  {
+    "name": "getTokenLargestAccounts",
+    "method": "getTokenLargestAccounts",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": [
+          {
+            "address": "DsZB2RSj7Ry9e69QzCAbg7oFhAUuNYzzFkPbhXSSGTBX",
+            "amount": "42000000",
+            "decimals": 6,
+            "uiAmount": 42.0,
+            "uiAmountString": "42"
+          }
+        ]
+      },
+      "id": 1
+    },
+    "params": [
+      "GLHHB8i4NhGbp5KvPkSb9sWwW5W2M9ExHhFGooF3qjrZ"
+    ]
+  },
+  {
+    "name": "getTokenAccountsByOwner",
+    "method": "getTokenAccountsByOwner",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": [
+          {
+            "account": {
+              "data": [
+                "48++7/3R0WIonJxD1BvrGy92zcSxFsK3EIlKgUiPsQKABUnlbzpEmD/B9Mne0UtewK8vglXadt4+j5gxsciGXYDegAIAAAAAAQAAAFwLTXcQ1RvynIymV4tqc6oCAPQkAOGMo+Zz71Y4tzRvAQAAAAAAAAAAAAAAAEBCDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+                "base64"
+              ],
+              "executable": false,
+              "lamports": 2039280,
+              "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+              "rentEpoch": 18446744073709551615,
+              "space": 165
+            },
+            "pubkey": "DsZB2RSj7Ry9e69QzCAbg7oFhAUuNYzzFkPbhXSSGTBX"
+          }
+        ]
+      },
+      "id": 1
+    },
+    "params": [
+      "9cjs2tCQQft8cR1bDXrRYerzkw1kS2Z2VvrMDhmzUnpU",
+      {
+        "mint": "GLHHB8i4NhGbp5KvPkSb9sWwW5W2M9ExHhFGooF3qjrZ"
+      },
+      {
+        "encoding": "base64"
+      }
+    ]
+  },
+  {
+    "name": "getTokenAccountsByDelegate",
+    "method": "getTokenAccountsByDelegate",
+    "response": {
+      "jsonrpc": "2.0",
+      "result": {
+        "context": {
+          "apiVersion": "2.1.16",
+          "slot": 1179
+        },
+        "value": [
+          {
+            "account": {
+              "data": [
+                "48++7/3R0WIonJxD1BvrGy92zcSxFsK3EIlKgUiPsQKABUnlbzpEmD/B9Mne0UtewK8vglXadt4+j5gxsciGXYDegAIAAAAAAQAAAFwLTXcQ1RvynIymV4tqc6oCAPQkAOGMo+Zz71Y4tzRvAQAAAAAAAAAAAAAAAEBCDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+                "base64"
+              ],
+              "executable": false,
+              "lamports": 2039280,
+              "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+              "rentEpoch": 18446744073709551615,
+              "space": 165
+            },
+            "pubkey": "DsZB2RSj7Ry9e69QzCAbg7oFhAUuNYzzFkPbhXSSGTBX"
+          }
+        ]
+      },
+      "id": 1
+    },
+    "params": [
+      "7CJWFMwehUcFsPqFpxbCrcZM5QwzkvFyhqTyMvbLd57t",
+      {
+        "mint": "GLHHB8i4NhGbp5KvPkSb9sWwW5W2M9ExHhFGooF3qjrZ"
       },
       {
         "encoding": "base64"
diff --git a/test/fixtures/transactions.json b/test/fixtures/transactions.json
--- a/test/fixtures/transactions.json
+++ b/test/fixtures/transactions.json
@@ -42,5 +42,13 @@
   {
     "hex": "01fcffc6cc51a4de7b7259f429eabff20a3a06fd71eaf9463baae5a1955eb6599778cc1576701e78db8398ce733d9c0e0a63021a4e4ce7c7de049f638bc3301002010002058a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c02020202020202020202020202020202020202020202020202020202020202022525252525252525252525252525252525252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000006a7d517192c568ee08a845f73d29788cf035c3145b21ab344d8062ea940000025bdedad9fd7d269184d58d8f80e149acc1ceb154afc3c77363d7859c1febf2e0203030204000404000000030200010c0200000000ca9a3b00000000",
     "name": "nonce-transfer-transaction"
+  },
+  {
+    "hex": "0154fc0db41825a24d786eb9f7a47d74fb95afd938f7bfddc62835a7e595b315e1726352424be259ad6ea9aceeed325215927098cc123a81f1bc52909a89cb0b06010001028a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c054a535a992921064d24e87160da387c7c35b5ddbc92bb81e41fa8404105448d0909090909090909090909090909090909090909090909090909090909090909010101000a68656c6c6f2d6d656d6f",
+    "name": "memo-only-transaction"
+  },
+  {
+    "hex": "01df408945661266863208084cc664f9116851f15f77eaed5f05888d124688922f47416eeb1f0e83ff4d71b4597b73eeb4c88e5f84456f55997e35236c1b8abd0880010001028a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c054a535a992921064d24e87160da387c7c35b5ddbc92bb81e41fa8404105448d0909090909090909090909090909090909090909090909090909090909090909010101000a68656c6c6f2d6d656d6f00",
+    "name": "v0-memo-only-transaction"
   }
 ]
