For the complete documentation index, see llms.txt. This page is also available as Markdown.

πŸ”₯Accelerated getProgramAccounts

Fast getProgramAccounts on Solana - Response times under 10ms

getProgramAccounts is one of the most expensive calls on Solana. On a standard RPC node, it scans raw account states on every request - slow by design, and worse under load. The root cause is structural: standard nodes have no index over account data, so every call triggers the same full scan regardless of how specific your filter is.

This is exactly what Shyft solves - Introducing Accelerated getProgramAccounts.

Shyft's Accelerated getProgramAccounts (or Accelerated gPA) resolves the most common queries in under 10ms, no code changes required.

Why the standard getProgramAccounts is slow?

A vanilla Solana validator has no index over account data. When you call getProgramAccounts with a memcmp filter, the node walks every account owned by that program and compares bytes at the given offset - one by one, on-the-fly, every time. For large programs like Raydium or the Token Program, which own millions of accounts, this can take anywhere from hundreds of milliseconds to tens of seconds.

What happens when we call getProgramAccounts on Solana

How it works

Standard Solana RPC nodes handle everything - block replay, vote processing, account state, and RPC queries - in one tightly coupled stack. When a getProgramAccounts call comes in, it competes for resources with everything else the validator is doing, and scans raw account state on every request.

Shyft's approach is different. The accounts engine runs on entirely separate hardware, decoupled from the RPC layer. It has one job: maintain a fast, structured view of account data for the programs and offsets that matter most, and serve read requests against it.

The single-process architecture

The entire engine runs as a single unified process - no external database connections, no network hops between components. Three responsibilities, one process:

  • gRPC ingestion: Streams account updates directly from the validator layer as they happen on-chain.

  • RocksDB indexing: Writes account state into an embedded key-value store, keyed by program + offset.

  • Stateless JSON-RPC: Serves getProgramAccounts reads directly from RocksDB - no external calls.

The Shyft Accounts Engine: How It Works

How acceleration is triggered

When a getProgramAccounts request arrives at the JSON-RPC layer, the engine checks two things: is this program in the accelerated set, and does the memcmp offset match a keyed index for that program? If both match, the result is served directly from RocksDB. If either condition is not met, the request falls through to the standard RPC path transparently - same response, just without the speed benefit.

No code changes required. Acceleration is applied at the RPC layer automatically. Your existing getProgramAccounts calls work as-is - the engine intercepts matching requests before they ever touch raw ledger state.

On-demand Acceleration: New program + offset combinations can be added in real time

The engine currently covers a pre-defined set of programs and offsets selected based on query patterns across the Shyft network. But new indexes are not a deployment - they are created on demand. If you regularly query a program or offset not yet in the accelerated set, reach out to the Shyft team. The index is created without downtime or service interruption, and acceleration applies from that point forward.

Accelerated programs & offsets

The following program + offset combinations are accelerated. Calls that match are served from the Shyft accounts engine.

Protocol
Program address
Accelerated offsets

Pump.fun AMM

pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA

0,43,75

Pump.fun

6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P

0

Raydium CLMM

CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK

0, 73, 105

Raydium AMM v4

675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8

400, 432

Raydium CPMM

CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C

168, 200

Meteora DLMM

LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo

0, 88, 120

Meteora DAMM v2

cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG

168, 200

Meteora DAMM v1

Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB

40, 72

Orca Whirlpool

whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc

0, 101, 181

Jupiter Lend/Borrow

jupr81YtYssSyPt8jbnGuiWon5f6x9TcDEFxYe3Bdzi

0

Drift

dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN

0, 136

PancakeSwap CLMM

HpNfyc2Saw7RKkQd8nEL4khUcuPhQ7WwY1B2qjx8jxFq

0, 73, 105

Address Lookup Table

AddressLookupTab1e1111111111111111111111111111

22

Solana Stake Program

Stake11111111111111111111111111111111111111

12

Need a program added? New indexes are created on demand without downtime. Reach out to the Shyft team with the program address and the offsets you query regularly.

How the Engine Handles Multiple Filters

Most real-world getProgramAccounts calls don't use a single filter. A trading bot querying Raydium CLMM pools might filter by token_mint_a at offset 73 and by token_mint_b at offset 107 simultaneously - narrowing the result to pools containing a specific trading pair. Here's how the engine handles it:

When one of your filters hits an accelerated offset:

The engine scans your filter set, identifies the accelerated offset, and resolves that filter first - regardless of where you placed it in the array. The accelerated lookup runs against the purpose-built index and returns a narrow result set immediately. Every remaining filter is then evaluated in-memory against that already-narrow set. Filter order in your request does not matter - the engine finds the fast path automatically.

Even though the accelerated offset 73 is second in the array, the engine resolves it first. The result is every CLMM pool where token_mint_a is WSOL - filtered further in-memory to those where token_mint_b is USDC. Two filters, one fast path.

When none of your filters hit an accelerated offset:

The engine falls through to the standard scan path β€” filters evaluated in order, full account set, no short-circuit. The request completes correctly, just without the speed benefit.

For programs in the accelerated set, including at least one filter at an accelerated offset is all it takes β€” the engine handles the rest.

Quick Start

A working example for getProgramAccounts Pump.fun AMM at offset 43 - in cURL, JavaScript & Rust - the fastest way to see the latency difference yourself.

Latency results

Tests were run from the AMS region, 10 requests at 1 req/s using Hey with a persistent TCP connection. Four programs were tested, each at one of their accelerated offsets.

Program
Offset
Avg
p50
p90

Raydium CLMM

73

8.7ms

7.8ms

15.2ms

Pump.fun AMM

43

8.3ms

7.9ms

11.7ms

Address Lookup Table

22

10.9ms

10.7ms

15.4ms

Orca Whirlpool

101

8.2ms

7.8ms

12.4ms

Tests used Hey, which keeps the TCP connection open after the first request - representative of real application behaviour where connections are reused.

Frequently Asked Questions

How do I know if my request was accelerated?

You don't need to - and that's intentional. If your request matches an accelerated program + offset, it resolves faster. If it doesn't, it falls through to the standard path. The response format is identical in both cases.

What exactly is the "offset" in a memcmp filter, and how was it determined?

Every account on Solana stores its data as a raw byte buffer. The structure of that buffer - which fields live at which byte positions - is defined by the program that owns the account. This layout is typically described in the program's IDL (Interface Definition Language).

The offset in a memcmp filter tells the RPC node: "start reading at byte N in the account data buffer, and compare those bytes against my value." So offset: 73 on Raydium CLMM means "compare starting at byte 73 of each pool account's data." Byte 73 in a CLMM pool account is where the token_mint_a field begins - so filtering there lets you find all pools involving a specific token.

You derive the correct offset by reading the program's IDL or inspecting its account struct definitions in the source code. For Anchor-based programs, each field has a known size and they stack sequentially - so you sum the byte sizes of all fields before the one you want. Shyft identified the most commonly queried fields across each protocol and accelerated those specific offsets.

Practical tip: If you're using a protocol SDK (e.g. @raydium-io/raydium-sdk or @orca-so/whirlpools-sdk), the SDK usually constructs the correct memcmp filter for you - you don't need to calculate the offset manually.

What do you pass as the "bytes" value in the filter?

The bytes value is whatever you're filtering for at that offset - encoded as base58 (default) or base64 depending on the encoding you specify. It is not a fixed value; it's the specific thing you're looking up.

In most DeFi use cases, the field at an accelerated offset is a public key - a token mint address, a pool authority, or a user wallet. So bytes is the base58 or base64 encoded public key you're searching for.

What happens if I pass multiple memcmp filters at different offsets?

Filter order does not matter. The engine automatically identifies the accelerated offset from whichever filters you pass and resolves it first - returning a narrow result set from the purpose-built index. Any additional filters are then applied against that already-narrow result set in memory.

Is this available on all Shyft RPC plans?

Accelerated gPA is included on all paid Shyft RPC plans with no additional configuration. It is not available in the free plan.

Can I request acceleration for a program not on the list?

Yes. New indexes are not a deployment - they are created in real time on demand without downtime or service interruption. Reach out to the Shyft team with the program address and the offsets you query regularly.

Last updated