<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: OrbitFlare RPC</title>
    <description>The latest articles on DEV Community by OrbitFlare RPC (@orbitflarerpc).</description>
    <link>https://dev.to/orbitflarerpc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3813769%2F9f10e588-ac4d-43c5-9207-b2c4b7b0a835.png</url>
      <title>DEV Community: OrbitFlare RPC</title>
      <link>https://dev.to/orbitflarerpc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/orbitflarerpc"/>
    <language>en</language>
    <item>
      <title>p-token: How Solana Rewrote Its Most Important Program</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Thu, 28 May 2026 17:24:06 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/p-token-how-solana-rewrote-its-most-important-program-3mhd</link>
      <guid>https://dev.to/orbitflarerpc/p-token-how-solana-rewrote-its-most-important-program-3mhd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; The SPL Token program is the most-used piece of code on Solana. Nearly every non-vote transaction touches it, and it was quietly burning about 10% of every block's compute. So Anza rewrote it from scratch in a zero-dependency framework called Pinocchio and got a token transfer down from 4,645 compute units to 76. Then came the scary part: they swapped the new code in at the same address the old program lived at, behind a feature gate, at an epoch boundary, while billions of dollars sat in accounts that point to it. This is p-token (SIMD-0266). It's byte-for-byte compatible, so your client code didn't change a line. It went live on mainnet in spring 2026, and most people never noticed. That was the whole idea. Below: what happened under the hood, why a transfer got 60x cheaper, how you replace the most important program on a $100B+ network while it's running, and the one thing that did change for anyone reading token data off the chain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's a program on Solana that your code calls more than any other, whether you wrote that call or not. Every USDC transfer. Every swap leg. Every memecoin mint, every NFT that's really an SPL token, every "wrap SOL" in a Jupiter route. It's the SPL Token program. It lives at &lt;code&gt;TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA&lt;/code&gt;, and for years it was one of the least efficient things on the network, for a simple reason: nobody thought about it. It just worked, so it never got touched.&lt;/p&gt;

&lt;p&gt;Then someone added it up. Token instructions were eating roughly &lt;strong&gt;10% of the compute units in every block&lt;/strong&gt;. Not 10% of token-related blocks. 10% of all blockspace, everywhere, all the time, for a program whose job is mostly "subtract here, add there."&lt;/p&gt;

&lt;p&gt;So Anza rewrote it. The new version is called &lt;strong&gt;p-token&lt;/strong&gt;. It does the exact same thing as the old one, byte-for-byte, for a fraction of the compute. Then they replaced the old program in place: same address, same accounts, live on mainnet. Almost nobody noticed. That last part is the one worth understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Expensive Cheap Thing on Solana
&lt;/h2&gt;

&lt;p&gt;Compute units are the scarce resource on Solana. Not money, not storage. Compute. Every block has a hard cap, currently 60M CU, with a 12M budget per account write lock. Every instruction draws from that cap. When blocks fill up, your transaction's priority comes down to &lt;strong&gt;fee per compute unit&lt;/strong&gt;. CU is the currency that actually rations blockspace.&lt;/p&gt;

&lt;p&gt;Against that backdrop, look at what the old SPL Token program charged for the single most common operation on the network:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A plain &lt;code&gt;Transfer&lt;/code&gt;: &lt;strong&gt;4,645 CU&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;TransferChecked&lt;/code&gt;: &lt;strong&gt;6,200 CU&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That sounds small until you remember how often it runs. &lt;code&gt;Transfer&lt;/code&gt; and &lt;code&gt;TransferChecked&lt;/code&gt; together are nearly half of all token-program activity, and the token program is ~10% of all blockspace. So you're paying that 4,645 on a huge number of transactions every day, and a big chunk of it isn't doing anything useful. Some of it was pure logging: before a single lamport moved, the program would write &lt;code&gt;Program log: Instruction: Transfer&lt;/code&gt; to the transaction log, and that one line burned around 103 CU.&lt;/p&gt;

&lt;p&gt;The waste wasn't in the logic. The logic of a token transfer is trivial. The waste was in everything wrapped around it: how the program received its accounts, how it parsed them, and how much machinery the standard Solana program model dragged in before the first useful line ran. p-token's whole idea is that you can keep the logic identical and throw away the wrapping.&lt;/p&gt;

&lt;p&gt;Here's what "throw away the wrapping" actually bought, per instruction:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Instruction&lt;/th&gt;
&lt;th&gt;p-token&lt;/th&gt;
&lt;th&gt;old SPL Token&lt;/th&gt;
&lt;th&gt;Saving&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;transfer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;4,645&lt;/td&gt;
&lt;td&gt;~98%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;transfer_checked&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;6,200&lt;/td&gt;
&lt;td&gt;~98%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;initialize_mint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;2,967&lt;/td&gt;
&lt;td&gt;~96%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;initialize_account&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;154&lt;/td&gt;
&lt;td&gt;4,527&lt;/td&gt;
&lt;td&gt;~97%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mint_to&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;119&lt;/td&gt;
&lt;td&gt;4,538&lt;/td&gt;
&lt;td&gt;~97%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;burn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;126&lt;/td&gt;
&lt;td&gt;4,753&lt;/td&gt;
&lt;td&gt;~97%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;approve&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;124&lt;/td&gt;
&lt;td&gt;2,904&lt;/td&gt;
&lt;td&gt;~96%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;close_account&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;2,916&lt;/td&gt;
&lt;td&gt;~96%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;freeze_account&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;146&lt;/td&gt;
&lt;td&gt;4,265&lt;/td&gt;
&lt;td&gt;~97%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sync_native&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;61&lt;/td&gt;
&lt;td&gt;3,045&lt;/td&gt;
&lt;td&gt;~98%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(Benchmark figures from the official &lt;a href="https://solana.com/upgrades/p-token" rel="noopener noreferrer"&gt;p-token upgrade page&lt;/a&gt; and SIMD-0266. Exact counts drift a few units between Solana releases and benchmark runs, but the shape doesn't.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's the whole pitch in one table. Same instruction set, same account layouts, same results, for &lt;strong&gt;95-98% less compute&lt;/strong&gt;. On a plain transfer, the operation Solana runs most, that's 4,645 CU down to 76: about &lt;strong&gt;60x cheaper&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What p-token Actually Is
&lt;/h2&gt;

&lt;p&gt;First, kill the most common misconception: &lt;strong&gt;p-token isn't a new token spec, isn't a Token-2022 successor, and isn't something you migrate to.&lt;/strong&gt; It's a from-scratch reimplementation of the existing SPL Token program, compatible byte-for-byte: same instruction discriminators, same account layouts, same error codes, same everything an outside observer can see. Hand it the bytes for an &lt;code&gt;InitializeMint&lt;/code&gt; instruction and it reads them the same way, writes the same account state, and returns the same errors as the program it replaces.&lt;/p&gt;

&lt;p&gt;The "p" is for &lt;strong&gt;Pinocchio&lt;/strong&gt;, the framework it's built on. Pinocchio is where the savings come from.&lt;/p&gt;

&lt;p&gt;Pinocchio began as a personal experiment by Fernando "Febo" Otero, an engineer at Anza, aimed at one specific frustration: the &lt;code&gt;solana-program&lt;/code&gt; crate historically dragged in a heavy, constantly churning dependency tree, and he wanted out. The experiment caught on inside Anza and absorbed enough of the team to become a real project, and a genuinely different way to write a Solana program. Its tagline is "Create Solana programs with no external dependencies attached," and it means that literally. It's &lt;code&gt;no_std&lt;/code&gt;, it has zero external crates, it lets you drop the heap allocator entirely, and it never copies your accounts into owned memory. It's a &lt;code&gt;solana-program&lt;/code&gt; replacement built for two things: minimum compute and minimum binary size.&lt;/p&gt;

&lt;p&gt;p-token, the rewrite of SPL Token on top of Pinocchio, was the proof. It shrank the program binary from &lt;strong&gt;131 KB to 95 KB&lt;/strong&gt; and cut compute by ~95%. Febo and Jon Cinque wrote it up as &lt;strong&gt;&lt;a href="https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0266-efficient-token-program.md" rel="noopener noreferrer"&gt;SIMD-0266: Efficient Token Program&lt;/a&gt;&lt;/strong&gt;, and that proposal is what carried it to mainnet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Compute Actually Went
&lt;/h2&gt;

&lt;p&gt;This part is useful even if you never touch p-token, because it explains why a normal Solana program costs more than its logic suggests.&lt;/p&gt;

&lt;p&gt;When the Solana runtime invokes your program, it hands over one thing: a pointer to a serialized byte buffer. That buffer holds the program ID, the accounts, and the instruction data, all packed into a specific layout. What your program does with it next is where frameworks split apart.&lt;/p&gt;

&lt;p&gt;The standard &lt;code&gt;solana-program&lt;/code&gt; entrypoint, the one almost every program uses, does the friendly thing. Before a single line of your logic runs, its &lt;code&gt;deserialize&lt;/code&gt; routine walks that buffer and builds owned Rust structures. It allocates a &lt;code&gt;Vec&amp;lt;AccountInfo&amp;gt;&lt;/code&gt; on the heap, and for every account it wraps the lamports and data in &lt;code&gt;Rc&amp;lt;RefCell&amp;lt;…&amp;gt;&amp;gt;&lt;/code&gt;, reference-counted smart pointers you can mutate through. That's convenient. It's also a pile of allocations and copies on every single invocation, and it grows with the number of accounts. You pay for it whether or not your program touches those accounts. It even sets up a heap allocator and a panic handler you may never use.&lt;/p&gt;

&lt;p&gt;Pinocchio refuses to do almost all of that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9zhlp77o7t2nmb6rbix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9zhlp77o7t2nmb6rbix.png" alt="Comparison Diagram" width="800" height="1132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pinocchio's account type is basically a typed pointer into the runtime's input buffer. It doesn't copy the account data anywhere. It reads lamports, owner, and data in place, through the pointer. That's what "zero-copy" means here. Instead of a heap &lt;code&gt;Vec&lt;/code&gt;, it writes those pointer-views into a fixed-size array on the stack. No &lt;code&gt;Rc&lt;/code&gt;, no &lt;code&gt;RefCell&lt;/code&gt;, no allocator, no &lt;code&gt;std&lt;/code&gt;. With one macro you can forbid heap allocation entirely, so the compiler guarantees your program never touches the heap.&lt;/p&gt;

&lt;p&gt;Most of the compute reduction came from two changes: replacing the standard entrypoint and switching to zero-copy account access. The rest came from dropping &lt;code&gt;solana-program&lt;/code&gt;, hand-writing the instruction dispatch, and removing the per-instruction log line. (Remember, that log line alone cost ~103 CU, pure overhead just to print the instruction's name.)&lt;/p&gt;

&lt;p&gt;The tradeoff is real, and worth saying plainly: Pinocchio is much more manual. No automatic account validation, no account model, no IDL generation, more &lt;code&gt;unsafe&lt;/code&gt;, more pointer arithmetic, more ways to shoot yourself in the foot. Anchor hands you guardrails. Pinocchio hands you the bare runtime and trusts you to check signers, ownership, and writability yourself. For a tiny, frozen-spec program like SPL Token, which gets audited to death and almost never changes, that's a fine bargain. For your app, it usually isn't. If you want a middle ground, Steel keeps zero-copy parsing but adds back some ergonomics. At the far extreme, there's hand-written sBPF assembly. Pinocchio sits close to that assembly end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Things It Can Do That the Old One Couldn't
&lt;/h2&gt;

&lt;p&gt;Byte-for-byte compatibility means p-token can't remove behavior. But it can add. SIMD-0266 ships three new instructions, all purely additive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;batch&lt;/code&gt; (discriminator 255).&lt;/strong&gt; This is the sleeper. A cross-program invocation has a fixed cost of roughly 1,000 CU just to make the call, before the called instruction does anything. A program that does several token operations in one transaction pays that ~1,000 CU every time. Think of an AMM handling a deposit: transfer A, transfer B, mint LP. Three calls, three times the entry cost. &lt;code&gt;batch&lt;/code&gt; lets you bundle multiple token instructions into a single invocation, so you pay the CPI entry cost once for the whole batch instead of once per instruction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;withdraw_excess_lamports&lt;/code&gt; (discriminator 38).&lt;/strong&gt; Over the years, people have accidentally sent plain SOL straight to mint and multisig accounts, where it just sits above the rent-exempt minimum with no way out. The total isn't small: something like &lt;strong&gt;177,000 SOL, tens of millions of dollars&lt;/strong&gt;, stuck in token mint accounts. This instruction lets the proper authority sweep that excess back out. (Discriminator 38 deliberately matches Token-2022's existing equivalent.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;unwrap_lamports&lt;/code&gt; (discriminator 45).&lt;/strong&gt; A cleaner path for native (wrapped) SOL. You move lamports straight out of a native token account to a destination, skipping the old dance of creating and closing a temporary account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Swapping the Engine While the Plane Is Flying
&lt;/h2&gt;

&lt;p&gt;Now for the audacious part.&lt;/p&gt;

&lt;p&gt;You have a program at &lt;code&gt;Tokenkeg…VQ5DA&lt;/code&gt;. Hundreds of billions of dollars of token accounts name it as their owner. Thousands of other programs call into it by that address. And its upgrade authority was burned long ago, so for all practical purposes it's immutable. You can't just send an upgrade transaction. So how do you replace its code without asking the whole ecosystem to migrate to a new address? Migrating was explicitly rejected, because adoption would crawl and most of the benefit would evaporate.&lt;/p&gt;

&lt;p&gt;You do it at the &lt;strong&gt;runtime level, behind a feature gate&lt;/strong&gt;, and you let consensus perform the swap atomically. Here's how it goes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pre-deploy the verified bytecode&lt;/strong&gt; to a separate staging address: &lt;code&gt;ptok6rngomXrDbWf5v5Mkmu5CEbB51hzSCPDoj9DrvF&lt;/code&gt;. This is just a holding pen. The audited code sits on-chain, where anyone can inspect it, before anything changes. That "ptok…" address is the source, not the destination.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ship the change behind a feature gate&lt;/strong&gt; (&lt;code&gt;ptokFjwyJtrwCa9Kgo9xoDS59V4QccBGEaRFnRPnSdP&lt;/code&gt;) inside a new validator release. Operators upgrade their software, but nothing actually switches yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vote.&lt;/strong&gt; Because this carries enormous economic weight, SIMD-0266 went to a stake-weighted validator vote and needed the standard supermajority of participating stake. It passed in early 2026.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Activate at an epoch boundary.&lt;/strong&gt; Once enough stake is running the new code, the feature gate flips. Every validator's runtime, in lockstep, replaces the executable at &lt;code&gt;Tokenkeg…VQ5DA&lt;/code&gt; with the bytecode from the staging address, through the Upgradeable BPF Loader. The address keeps its identity. Only the code behind it changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The swap doesn't go through the normal upgrade path, so the frozen upgrade authority never gets in the way. The validators just agree to run the new code at the next epoch boundary. p-token went live on Solana mainnet in spring 2026, at &lt;strong&gt;epoch 971&lt;/strong&gt;. To stay in sync, validators needed Agave v3.1.7+ or Firedancer v0.812.30108+. Devnet had switched over earlier. For almost everyone (users, wallets, and other programs), the only thing they noticed was that token transactions got cheaper. Nothing to update, nothing to migrate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rewriting the Crown Jewels Without Losing Them
&lt;/h2&gt;

&lt;p&gt;Here's the question that should make any serious engineer nervous. You just rewrote, from scratch, in a framework that leans heavily on &lt;code&gt;unsafe&lt;/code&gt; and raw pointers, the single program that holds the largest share of value on Solana. Then you atomically replaced the old one with it. A subtle bug here isn't a worse user experience. It's the backbone of every DeFi position on the network behaving differently than the code that secured it yesterday. How do you ever get comfortable with that?&lt;/p&gt;

&lt;p&gt;The answer is one of the more interesting safety-engineering stories in recent Solana history, and it's worth knowing, because it isn't "we audited it and hoped."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Differential testing against real history (Neodyme).&lt;/strong&gt; This is the strongest pillar. Neodyme built a harness in their Riverguard fuzzer that replayed essentially every mainnet transaction that ever touched the token program through both programs, old and p-token, and diffed the results. The question wasn't "do the tests pass." It was "given the actual transactions that really happened on Solana over months, does the new program produce byte-identical account state, the same metadata, and the same error codes, in the same priority order, as the old one?" After months of running: &lt;strong&gt;not a single divergence.&lt;/strong&gt; The same harness measured the payoff. Over one sample window (Aug 3-11, 2025), p-token would have saved &lt;strong&gt;8.9-9.1 trillion compute units, about 12% of the entire chain's blockspace&lt;/strong&gt;, vote transactions and all. That 12% is the honest, auditor-measured number to anchor on, more so than the per-instruction headline percentages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Independent audits that actually found things (Zellic).&lt;/strong&gt; Zellic audited both Pinocchio and p-token and surfaced &lt;strong&gt;8 findings, one Critical and three High&lt;/strong&gt;. Among them: an out-of-bounds read in a memory-copy helper (&lt;code&gt;copy_val&lt;/code&gt;) caused by a loose generic bound, plus several memory-safety traps from the heavy use of &lt;code&gt;unsafe&lt;/code&gt; and &lt;code&gt;MaybeUninit&lt;/code&gt;. All were fixed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The bug that proves the point (Asymmetric Research).&lt;/strong&gt; Before mainnet, Asymmetric Research found a real loss-of-funds bug. Tellingly, it lived in the new functionality, not the replicated logic. As an optimization, p-token defers some ownership checks to the runtime's end-of-transaction validation. The new &lt;code&gt;batch&lt;/code&gt; instruction runs multiple state transitions in one invocation. Combine the two and you could craft a fake native-token account, bump a victim's wrapped-SOL balance with no real lamports to back it, then restore the fake account's bytes before the runtime's ownership check ran. The tampering was invisible to validation. The fix was to add explicit ownership checks to &lt;code&gt;batch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Formal verification (Runtime Verification)&lt;/strong&gt; rounds out the stack as a third independent leg. Alongside it sit Anza's own differential fuzzer, which by Neodyme's account had already caught everything Neodyme later flagged, and Firedancer's fuzzing tools.&lt;/p&gt;

&lt;p&gt;Stack it all up, and the case for trusting p-token isn't "trust us." It's a hard, narrow spec: be byte-identical to a program we've run for years. That spec got checked against real chain history at scale. Multiple independent teams attacked it and found real bugs, which got fixed. Formal proofs went on top. And the whole thing rolled out behind a vote and a feature gate, so it only switched on once the network agreed. The leftover risk isn't zero. It never is. But it was driven down about as carefully as a change like this can be.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Changes for You
&lt;/h2&gt;

&lt;p&gt;For most people building on Solana, the honest answer is &lt;strong&gt;nothing&lt;/strong&gt;. Your client code keeps working, because the instruction and account layouts are identical. Your transfers just got cheaper. Done.&lt;/p&gt;

&lt;p&gt;But there are two groups who should pay attention, and because you're reading an OrbitFlare post you're probably in one of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you index or stream token activity, the logs changed.&lt;/strong&gt; Remember that ~103 CU log line p-token deleted? A lot of indexers identified token instructions by scraping exactly that text, matching on &lt;code&gt;Program log: Instruction: Transfer&lt;/code&gt; to label what happened. p-token doesn't emit it. If your pipeline leans on log strings to classify token instructions, it goes blind on the new program. The fix is the thing you should have been doing anyway: &lt;strong&gt;decode the instruction data against the IDL&lt;/strong&gt; instead of reading prose out of logs. The updated IDL ships in the &lt;code&gt;solana-program/token&lt;/code&gt; repo, with refreshed clients (&lt;code&gt;@solana-program/token&lt;/code&gt; and &lt;code&gt;spl-token-client&lt;/code&gt;) that expose the new instructions. This is the one concrete migration the upgrade forces, and it lands on data infrastructure, not on apps. If you consume a stream that already hands you decoded, structured transactions, this was a non-event. If you built your own log-scraping layer, this is your cue to retire it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you trade, the priority math shifted.&lt;/strong&gt; Priority is fee per compute unit. A token-heavy transaction that now burns a fraction of the CU it used to can command higher priority for the same fee or tip, or hold the same priority for less. And clawing ~10% of compute back into every block raises the ceiling on how much the network can do before blocks fill. If your edge depends on landing transactions during congestion, both of those are worth re-tuning around.&lt;/p&gt;

&lt;p&gt;And for everyone: the most-used program on the chain is now one of the smallest, fastest, most-scrutinized things on it. That's a good direction for the whole stack you're building on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Quiet Upgrade
&lt;/h2&gt;

&lt;p&gt;The flashy Solana upgrades get the headlines: Firedancer, new consensus, bigger blocks. p-token got almost none of that, and it may end up mattering more day-to-day than any of them, precisely because it touches the one program everything else routes through. It didn't add a feature. It took the single most common thing the network does, made it about 60x cheaper, and slid the new engine in under the old one's address without asking anyone to change a line.&lt;/p&gt;

&lt;p&gt;That's the kind of upgrade you only notice if you go looking at the compute meter. Which, if your business runs on Solana, is exactly where you should be looking.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://orbitflare.com" rel="noopener noreferrer"&gt;OrbitFlare&lt;/a&gt; builds the infrastructure under Solana apps: RPC, WebSocket, Yellowstone gRPC, Jetstream shred-decoded streaming, and Shredstream.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0266-efficient-token-program.md" rel="noopener noreferrer"&gt;SIMD-0266: Efficient Token Program&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://solana.com/upgrades/p-token" rel="noopener noreferrer"&gt;Solana: Optimized Token Program (p-token)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/anza-xyz/pinocchio" rel="noopener noreferrer"&gt;Pinocchio framework (anza-xyz/pinocchio)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://neodyme.io/reports/P-Token.pdf" rel="noopener noreferrer"&gt;Neodyme p-token audit (PDF)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://reports.zellic.io/publications/pinocchio-and-p-token" rel="noopener noreferrer"&gt;Zellic: Pinocchio and p-token audit&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://blog.asymmetric.re/solana-p-token-catching-a-bug-before-mainnet/" rel="noopener noreferrer"&gt;Asymmetric Research: Catching a Bug Before Mainnet&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/solana-program/token" rel="noopener noreferrer"&gt;solana-program/token repository&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>solana</category>
      <category>ptoken</category>
      <category>orbitflare</category>
      <category>pinocchio</category>
    </item>
    <item>
      <title>Building a Live Solana TPS Meter with OrbitFlare's TypeScript SDK</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Fri, 22 May 2026 21:18:18 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/building-a-live-solana-tps-meter-with-orbitflares-typescript-sdk-b66</link>
      <guid>https://dev.to/orbitflarerpc/building-a-live-solana-tps-meter-with-orbitflares-typescript-sdk-b66</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknn46spbnxs8nyxr4p70.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknn46spbnxs8nyxr4p70.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every Solana dashboard tells you the network's TPS. None of them tell you how busy the one program you care about is right now. Did Pumpfun cool off after a launch? Is Raydium spiking? Is the program your bot listens to still alive in the last 30 seconds? You're stuck picking between a smoothed-out aggregate or a paid dashboard that refreshes once a minute.&lt;/p&gt;

&lt;p&gt;The smallest thing that answers the question directly is below. Point it at any Solana program, get a live transactions-per-second gauge in the terminal with a recent-signatures tape under it. One TypeScript file, less than 100 LoC, runs in a terminal, built on &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@orbitflare/sdk" rel="noopener noreferrer"&gt;&lt;code&gt;@orbitflare/sdk&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jetstream tx rate: pumpfun (6EF8rrec...)
chain slot:        421442130

last 1s:     14 tx/s
last 10s:    9.7 tx/s avg

recent signatures:
   0.1s ago  slot 421442129  4bpPQBUHmobNJ4SS9ETLaMwY...
   0.4s ago  slot 421442128  Gsi3P32j6h9Yx3ce1gfHR5Pa...
   0.7s ago  slot 421442128  55AWdcey9N1WTYkmQDXPeKHD...
   ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full source: &lt;a href="https://github.com/orbitflare/jetstream-tx-rate" rel="noopener noreferrer"&gt;github.com/orbitflare/jetstream-tx-rate&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest meter problem
&lt;/h2&gt;

&lt;p&gt;The meter could be built with one Jetstream subscription: filter on the program, count transactions per second. That gets done in 50 lines. The problem only shows up the first time the program goes quiet for ten seconds. The meter reads zero. So does the signature tape. And now there's no way to know whether the program is actually idle or whether the SDK silently lost the connection three minutes ago.&lt;/p&gt;

&lt;p&gt;The fix is one extra subscription on a second transport. WebSocket &lt;code&gt;slotSubscribe()&lt;/code&gt; ticks every ~400ms whether anything is happening or not, because the chain itself never stops.&lt;/p&gt;

&lt;h2&gt;
  
  
  The clients
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JetstreamClientBuilder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@orbitflare/sdk/jetstream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WsClientBuilder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@orbitflare/sdk/ws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JetstreamClientBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://jp.jetstream.orbitflare.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WsClientBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws://ams.rpc.orbitflare.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it for setup. Jetstream needs no api key. WebSocket picks one up from &lt;code&gt;ORBITFLARE_LICENSE_KEY&lt;/code&gt; if set.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two subscriptions
&lt;/h2&gt;

&lt;p&gt;WebSocket pipes the chain slot into a shared variable. One callback, no state machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentSlot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;slotSub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slotSubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;slotSub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;slot&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;currentSlot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetstream gets the transaction firehose, filtered server-side to just the program of interest. &lt;code&gt;for await&lt;/code&gt; drains it and stamps each arrival:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;accountInclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
      &lt;span class="na"&gt;accountExclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
      &lt;span class="na"&gt;accountRequired&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="na"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrivals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;arrivals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bs58&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;accountRequired&lt;/code&gt; filter is the load-bearing piece. It tells the Jetstream server to only ship transactions where the program is in the account list, so the bandwidth that reaches the laptop is already the data that matters. No client-side filtering, no wasted parsing.&lt;/p&gt;

&lt;p&gt;Two pieces of state, both trivial. &lt;code&gt;arrivals&lt;/code&gt; is a list of millisecond timestamps the renderer reads to compute rates. &lt;code&gt;recent&lt;/code&gt; is a 10-element ring of the most recent signatures, kept in arrival order, displayed as a scrolling tape under the gauge.&lt;/p&gt;

&lt;h2&gt;
  
  
  The renderer
&lt;/h2&gt;

&lt;p&gt;Every second, the renderer does three things. First it drops any timestamp older than 10 seconds from &lt;code&gt;arrivals&lt;/code&gt;. Then it counts: how many timestamps in the last 1 second (that's the instantaneous rate), and the total count divided by 10 (that's the rolling 10-second average). Finally it clears the screen with an ANSI escape and prints the dashboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrivals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;arrivals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;arrivals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;last1s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arrivals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;last10sAvg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arrivals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s1"&gt;x1B[2J&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s1"&gt;x1B[H&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`jetstream tx rate: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;...)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`chain slot:        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentSlot&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`  last 1s:  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;last1s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; tx/s`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`  last 10s: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;last10sAvg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; tx/s avg\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recent signatures:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;s ago  slot &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/orbitflare/jetstream-tx-rate.git
&lt;span class="nb"&gt;cd &lt;/span&gt;jetstream-tx-rate
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm start pumpfun       &lt;span class="c"&gt;# or raydium, jupiter, or any raw program id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Signatures land within a second of the first run. Watching Pumpfun for five minutes shows it idling around 8-15 tx/s on a slow afternoon and spiking to 50-80 when a launch hits. Raydium runs lighter on average but every big swap is a visible jolt. Any program ID on Solana gets the same view of how busy it actually is, not how busy it averages out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this tiny snippet doesn't have to do
&lt;/h2&gt;

&lt;p&gt;Reconnects, regional failover, api-key scrubbing, ping/pong liveness, the protobuf wire format, the WebSocket re-subscribe dance after a drop. The SDK handles all of it the same way across both transports. None of it shows up in the source. What's left is a filter, a callback, and the rendering math.&lt;/p&gt;

&lt;p&gt;That’s the trade. And a good one. Use the SDK’s plumbing, write the part that’s actually yours.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/orbitflare/jetstream-tx-rate" rel="noopener noreferrer"&gt;Full source: github.com/orbitflare/jetstream-tx-rate&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@orbitflare/sdk" rel="noopener noreferrer"&gt;&lt;code&gt;@orbitflare/sdk&lt;/code&gt; on npm&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.orbitflare.com/sdk/typescript-rpc" rel="noopener noreferrer"&gt;SDK docs&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>blockchain</category>
      <category>solana</category>
      <category>websocket</category>
      <category>orbitflare</category>
    </item>
    <item>
      <title>Three new ways into OrbitFlare: Introducing the CLI, MCP, and Skills</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Wed, 13 May 2026 06:53:29 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/three-new-ways-into-orbitflare-introducing-the-cli-mcp-and-skills-516o</link>
      <guid>https://dev.to/orbitflarerpc/three-new-ways-into-orbitflare-introducing-the-cli-mcp-and-skills-516o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gqi56xqymy3xcun2ytf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gqi56xqymy3xcun2ytf.png" alt="Article Banner" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
You write a Solana app and the questions that come up while you're writing it almost never live in the same place as the code. You want a fee sample for an address that touches Raydium so you can decide whether your priority-fee bid is going to land or sit. You want to know what your account balance is before you spin up a heavier plan. You want to scaffold a copy-trader because you've thought of a strategy and you'd rather see it move on chain before you talk yourself out of it. You want your editor's AI to stop hallucinating gRPC field names that haven't existed since the Yellowstone proto last changed.&lt;/p&gt;

&lt;p&gt;Every one of those is a context switch. Tab over to the dashboard, click through. Open a new terminal, dig out the right curl. Re-explain to the agent that no, this is Jetstream's proto, not Yellowstone's, and the field is &lt;code&gt;account_include&lt;/code&gt;, not &lt;code&gt;account_filter&lt;/code&gt;. Each one is small. They add up.&lt;/p&gt;

&lt;p&gt;The three things below close those gaps where they actually live: in your terminal, in your agent's context window, and in the chat surface where you're already typing.&lt;/p&gt;
&lt;h2&gt;
  
  
  The CLI
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;orbitflare&lt;/code&gt; is a single binary that puts every piece of the OrbitFlare surface area one command away from your shell. RPC queries, two flavors of gRPC streaming, WebSocket subscriptions, project scaffolding from a small library of templates, login and key management, plan browsing, on-chain top-ups in USDC, and a TUI dashboard for watching the whole account move in real time. Every command supports &lt;code&gt;--json&lt;/code&gt;, so you can pipe any output into the next thing in the chain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;orbitflare
orbitflare auth login &lt;span class="nt"&gt;--x-orbit-key&lt;/span&gt; ORBIT-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the install and the one-time login. Credentials land in the OS keychain, the RPC license key gets pulled in for you so you don't have to thread it through every command, and &lt;code&gt;orbitflare auth status&lt;/code&gt; is there when you need to confirm which profile you're talking to.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rpc&lt;/code&gt; handles one-shot reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;orbitflare rpc slot
orbitflare rpc balance &amp;lt;ADDRESS&amp;gt;
orbitflare rpc tokens &amp;lt;WALLET&amp;gt;
orbitflare rpc tx &amp;lt;SIGNATURE&amp;gt;
orbitflare rpc &lt;span class="nb"&gt;history&lt;/span&gt; &amp;lt;WALLET&amp;gt; &lt;span class="nt"&gt;--limit&lt;/span&gt; 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ws&lt;/code&gt; mirrors Solana's four pubsub subscription types. Each takes a &lt;code&gt;--commitment&lt;/code&gt; to override the default and a &lt;code&gt;--json&lt;/code&gt; flag for one-line-per-update output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;orbitflare ws slot
orbitflare ws account EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
orbitflare ws logs &lt;span class="nt"&gt;--mentions&lt;/span&gt; 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
orbitflare ws signature &amp;lt;sig&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--ws-url&lt;/code&gt; is global and auto-derived from your RPC URL when you don't pass one, which is most of the time.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jet&lt;/code&gt; and &lt;code&gt;grpc&lt;/code&gt; are the firehoses. Both take a YAML config that describes which transactions, accounts, or slots you want to see, expand &lt;code&gt;${ENV_VAR}&lt;/code&gt; references inline, and stream the matching events as they happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;orbitflare jet &lt;span class="nt"&gt;--config&lt;/span&gt; stream.yml
orbitflare grpc &lt;span class="nt"&gt;--config&lt;/span&gt; grpc-stream.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;template --list&lt;/code&gt; shows what's available and &lt;code&gt;template --install &amp;lt;name&amp;gt;&lt;/code&gt; clones the chosen example into your working directory, which is the fastest way to see how an OrbitFlare-shaped project is wired end to end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;orbitflare template &lt;span class="nt"&gt;--install&lt;/span&gt; solana-copy-trader
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;plan list&lt;/code&gt;, &lt;code&gt;plan compare --all&lt;/code&gt;, &lt;code&gt;pay check-balance&lt;/code&gt;, and &lt;code&gt;pay topup &amp;lt;AMOUNT&amp;gt;&lt;/code&gt; cover the account side, the same things you'd otherwise be clicking through the dashboard to reach. &lt;code&gt;dashboard&lt;/code&gt; opens the TUI when you want all of it in one panel.&lt;/p&gt;

&lt;p&gt;Streaming and RPC inside the CLI run on top of the published &lt;code&gt;orbitflare-sdk&lt;/code&gt; crate, which means multi-endpoint failover, exponential retry with jitter, active ping/pong liveness checks, automatic reconnection on disconnect, and URL sanitization that keeps your api key out of error messages and tracing spans all come along for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skills
&lt;/h2&gt;

&lt;p&gt;If you've spent any time in Claude Code, Cursor, or Codex, you've already noticed the model is confident about Solana in general and confidently wrong about Solana specifics maybe a third of the time. It writes you a &lt;code&gt;getProgramAccounts&lt;/code&gt; call without the &lt;code&gt;dataSlice&lt;/code&gt; you almost certainly need. It assumes Jetstream's proto looks like Yellowstone's because Yellowstone is what's in its training set and Jetstream isn't. It invents CLI flags that don't exist because flag shapes are the kind of thing models are happy to extrapolate.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@orbitflare/skills&lt;/code&gt; fixes the OrbitFlare half of that. One npx command drops the skill into your agent's skills directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @orbitflare/skills@latest                &lt;span class="c"&gt;# ~/.claude/skills/orbitflare&lt;/span&gt;
npx @orbitflare/skills@latest &lt;span class="nt"&gt;--project&lt;/span&gt;      &lt;span class="c"&gt;# ./.claude/skills/orbitflare&lt;/span&gt;
npx @orbitflare/skills@latest &lt;span class="nt"&gt;--cursor&lt;/span&gt;       &lt;span class="c"&gt;# ~/.cursor/skills-cursor/orbitflare&lt;/span&gt;
npx @orbitflare/skills@latest &lt;span class="nt"&gt;--codex&lt;/span&gt;        &lt;span class="c"&gt;# ~/.codex/skills/orbitflare&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;SKILL.md&lt;/code&gt; and a &lt;code&gt;references/&lt;/code&gt; folder land on disk, all pulled straight from the official documentation. The contents cover the things a generic Solana training set tends to miss. Which transport fits which question. The two-key model: &lt;code&gt;?api_key=&lt;/code&gt; on the URL for chain reads, &lt;code&gt;X-ORBIT-KEY&lt;/code&gt; in a header for the Customer API. What &lt;code&gt;getTransactionsForAddress&lt;/code&gt; does in one call that stock &lt;code&gt;getSignaturesForAddress&lt;/code&gt; plus a &lt;code&gt;getTransaction&lt;/code&gt; fan-out can't match. The exact YAML shape &lt;code&gt;orbitflare grpc&lt;/code&gt; and &lt;code&gt;orbitflare jet&lt;/code&gt; expect.&lt;/p&gt;

&lt;p&gt;Restart the agent and try something you'd otherwise have to spell out the long way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Stream Pump.fun trades using OrbitFlare Jetstream.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent reaches into the skill, writes a &lt;code&gt;jetstream.yml&lt;/code&gt; with the right &lt;code&gt;account_include&lt;/code&gt;, and hands you back the &lt;code&gt;orbitflare jet --config jetstream.yml&lt;/code&gt; to run. Ask for the same thing in Rust and it pulls in &lt;code&gt;orbitflare-sdk&lt;/code&gt; with the &lt;code&gt;jetstream&lt;/code&gt; feature and writes out the &lt;code&gt;JetstreamClientBuilder&lt;/code&gt; chain. The model could have guessed something plausible on its own. With the skill, the first guess is the right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MCP server
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@orbitflare/mcp&lt;/code&gt; is an MCP server that exposes 53 OrbitFlare capabilities as discrete tools, one per capability, so any MCP host (Claude Desktop, Claude Code, Cursor, Windsurf, Codex CLI, Gemini CLI, VS Code) can call them directly from the chat window.&lt;/p&gt;

&lt;p&gt;Most hosts share the same JSON block, pointed at npx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"orbitflare"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@orbitflare/mcp@latest"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ORBITFLARE_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-license-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ORBITFLARE_NETWORK"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mainnet"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file path varies by host (Claude Desktop's &lt;code&gt;claude_desktop_config.json&lt;/code&gt;, Cursor's &lt;code&gt;~/.cursor/mcp.json&lt;/code&gt;, Codex CLI's TOML at &lt;code&gt;~/.codex/config.toml&lt;/code&gt;), but the shape is the same. If you'd rather not put the key in the host config, drop the env block and call &lt;code&gt;setApiKey&lt;/code&gt; from the chat once.&lt;/p&gt;

&lt;p&gt;MCP works best when the question maps cleanly to a single capability. The model picks the tool, you don't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;What's a competitive priority fee right now for an account that touches Raydium?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That fans out to &lt;code&gt;getRecentPrioritizationFees&lt;/code&gt; with the right address, and the model summarizes the P50/P75/P90/P99 percentiles into chat. You don't have to know the JSON shape of the response.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Build me a Yellowstone gRPC config that streams Jupiter swap transactions from Frankfurt.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That hits &lt;code&gt;subscribeTransactions&lt;/code&gt;, which returns a ready-to-use YAML you can drop straight into &lt;code&gt;orbitflare grpc --config&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Quote 1 SOL to USDC with 0.3% slippage.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That hits &lt;code&gt;getSwapQuote&lt;/code&gt;, which runs through Jupiter Metis routing. &lt;code&gt;SOL&lt;/code&gt; and &lt;code&gt;USDC&lt;/code&gt; get auto-resolved to their mint addresses, and the response carries the route, expected output, and price impact.&lt;/p&gt;

&lt;p&gt;All 53 tools are independently callable. No internal action router, no pagination dance for large payloads, and &lt;code&gt;setApiKey&lt;/code&gt; swaps either of the two keys at runtime.&lt;/p&gt;

&lt;p&gt;The docs are also exposed as MCP resources under &lt;code&gt;orbitflare://docs/*&lt;/code&gt;, so the model grounds answers in pages it can actually quote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three places, one stack
&lt;/h2&gt;

&lt;p&gt;Three different surfaces, same stack underneath. Same license keys. Same eleven regions (&lt;code&gt;ash&lt;/code&gt;, &lt;code&gt;ny&lt;/code&gt;, &lt;code&gt;la&lt;/code&gt;, &lt;code&gt;slc&lt;/code&gt;, &lt;code&gt;ams&lt;/code&gt;, &lt;code&gt;fra&lt;/code&gt;, &lt;code&gt;lon&lt;/code&gt;, &lt;code&gt;dub&lt;/code&gt;, &lt;code&gt;siau&lt;/code&gt;, &lt;code&gt;tok&lt;/code&gt;, &lt;code&gt;sgp&lt;/code&gt;). Same docs, just exposed differently to whichever surface is asking.&lt;/p&gt;

&lt;p&gt;Pick whichever fits how you work. The CLI when you're in a shell. The skill when you're in your IDE with an agent open. The MCP server when you're in a chat window and would rather not turn the question into a coding task in the first place. You'll probably end up with all three.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://crates.io/crates/orbitflare" rel="noopener noreferrer"&gt;&lt;code&gt;orbitflare&lt;/code&gt; on crates.io&lt;/a&gt;&lt;/strong&gt; (CLI v0.3)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@orbitflare/skills" rel="noopener noreferrer"&gt;&lt;code&gt;@orbitflare/skills&lt;/code&gt; on npm&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@orbitflare/mcp" rel="noopener noreferrer"&gt;&lt;code&gt;@orbitflare/mcp&lt;/code&gt; on npm&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.orbitflare.com" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you build something with any of these, or run into a rough edge that should be smoother, we'd love to &lt;strong&gt;&lt;a href="https://discord.gg/orbitflare" rel="noopener noreferrer"&gt;hear&lt;/a&gt;&lt;/strong&gt; about it and help you out.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>ai</category>
      <category>orbitflare</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Top Solana RPC Providers in 2026 - A Comprehensive Guide</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Fri, 01 May 2026 18:46:34 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/top-solana-rpc-providers-in-2026-a-comprehensive-guide-5hck</link>
      <guid>https://dev.to/orbitflarerpc/top-solana-rpc-providers-in-2026-a-comprehensive-guide-5hck</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsd3wkqzf2578prsn9mvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsd3wkqzf2578prsn9mvm.png" alt="Banner" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a long time, picking a Solana RPC provider was a one-line decision: pick the cheapest endpoint that didn't fall over. The interesting question was whether you could afford a dedicated node or had to live on shared infrastructure. That world is mostly gone.&lt;/p&gt;

&lt;p&gt;In 2026, "Solana RPC" usually means a stack of five things that used to be distinct products. Plain JSON-RPC is the floor. On top of it sit WebSocket subscriptions, Yellowstone-style gRPC streams, shred-level feeds tapped before validators finish execution, and staked transaction submission with SWQoS routing. Most of the providers below offer some subset. A few offer all of them. At least two of the names you keep seeing on these lists don't really play the same game anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Actually Benchmark
&lt;/h2&gt;

&lt;p&gt;Reading a provider's website is not benchmarking. Five things worth putting on a real test rig from your own infrastructure before signing anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;p99 latency on the methods your app actually calls.&lt;/strong&gt; Average latency is marketing. The slowest 1% of requests is what breaks production. Pick the three or four methods that dominate your traffic (&lt;code&gt;getAccountInfo&lt;/code&gt;, &lt;code&gt;sendTransaction&lt;/code&gt;, &lt;code&gt;simulateTransaction&lt;/code&gt;, &lt;code&gt;getSignaturesForAddress&lt;/code&gt; are typical) and measure p99 from your own server for at least an hour during real chain activity. The gap between providers shows up in the long tail, not the median.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Transaction land rate during congestion.&lt;/strong&gt; Pick a known busy window (a vote epoch transition, a major mint, a memecoin event) and submit a few hundred test transactions through each provider you're evaluating. Track what percentage land on the first try. Staked submission and SWQoS routing typically push this into the high 90s; unprioritized submission can fall into the 60s. Land rate at p50 congestion is the number every provider quotes; land rate at p99 is the one that matters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reconnect behavior under partial failure.&lt;/strong&gt; Most providers' SDKs survive a clean disconnect. The interesting case is a flaky upstream: connection technically alive, packets dropping, slot lag silently growing. Simulate it (&lt;code&gt;tc qdisc add dev eth0 netem loss 5%&lt;/code&gt; on Linux is one easy approach) and watch whether the client recovers, retries, or just keeps yielding stale data. Whoever hides the failure longest hurts you the most.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The pricing curve at 10x your current load.&lt;/strong&gt; Free tiers and starter plans are decoys. The real number is what the bill becomes at the volume you'd hit if your product worked. Build a quick spreadsheet: project your request mix to 10x scale, run it through each provider's pricing page, see which ones double, which ones quadruple, and which ones quietly switch you to a custom-quote tier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The shape of what's above plain JSON-RPC.&lt;/strong&gt; Raw RPC is a commodity. The actual differentiators are the surfaces above it: parsed transactions, token and NFT metadata APIs, shred-level feeds, regional pops, archival depth, observability dashboards. Match your real needs against what each provider has shipped, not what they list on a coming-soon page. If a feature isn't documented, it doesn't exist for buying purposes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. OrbitFlare
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Facfnqfqnl8jcnr18n466.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Facfnqfqnl8jcnr18n466.png" alt="OrbitFlare Website" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OrbitFlare runs the full transport stack for Solana: RPC, WebSocket, Yellowstone-compatible gRPC, and two shred-layer products. Jetstream delivers decoded shreds over gRPC (the server parses the transaction for you), while Shredstream forwards raw shreds over UDP straight from top-of-Turbine validators in 9 regions. Coverage spans 11 regional pops on three continents: four in the US (Ashburn, New York, Los Angeles, Salt Lake City), five in Europe (Amsterdam, Frankfurt, London, Dublin, Siauliai), and two in Asia (Tokyo, Singapore). A single SDK talks to all four transports through one builder pattern, which kills the per-transport plumbing tax any non-trivial Solana app eventually accumulates.&lt;/p&gt;

&lt;p&gt;The Jetstream path sits closer to the leader than any Geyser-based feed by definition. Geyser fires after the validator commits the transaction. Shred decoding produces a parsed transaction before that. For anyone timing entries on swap rumors, copy-trading an active wallet, or detecting pool creations before they're in a block, that window matters.&lt;/p&gt;

&lt;p&gt;What OrbitFlare doesn't ship: NFT-heavy parsing APIs and cross-chain coverage. If those are the problem, Helius and QuickNode are the right calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Triton One
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfsx49jqwkjpj5tp2mjv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfsx49jqwkjpj5tp2mjv.png" alt="Triton Website" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Triton built Yellowstone. That alone earns them a top spot on any honest list, because the standard everyone else implements is the standard they wrote. Their public products read like an institutional menu: Dragon's Mouth for live gRPC, Steamboat for archival queries, Old Faithful for historical block data, Cascade Marketplace for SWQoS routing.&lt;/p&gt;

&lt;p&gt;They run dedicated nodes by default. Observed latency sits around 100ms, which is competitive with anyone. They have the longest credible track record powering large protocols. Openbook, Pyth, and Wormhole have all leaned on Triton at various points, and that kind of operational reputation isn't bought, it accumulates.&lt;/p&gt;

&lt;p&gt;The catch is the price tag. Dedicated nodes start in the high four figures per month, with Cascade pricing on top if staked submission is needed. Triton is institutional infrastructure and prices itself that way. For something that genuinely needs the guarantees they offer (large DeFi, exchange backends, capital-heavy MEV operations), they're worth the spend. For a side project a few months in, the pricing page is the bouncer.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Helius
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctaqp9vrt0lif5xnywd0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctaqp9vrt0lif5xnywd0.png" alt="Helius Website" width="799" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Helius is the Solana-native incumbent, and usually the right answer when the requirement is "I need a lot of Solana-specific tooling and I want it now." Their RPC runs through staked validator nodes for SWQoS priority on transaction submission. Beyond plain RPC, they ship an Enhanced Transactions API, the Digital Asset Standard (DAS) read API, parsed webhooks, and LaserStream for low-latency gRPC.&lt;/p&gt;

&lt;p&gt;If your app is heavy on token metadata, NFT data, or anything that would otherwise require a custom indexer to enrich raw RPC output, Helius has done that work and exposes it under one account. Their free tier at 1M credits per month is one of the more generous on this list, which makes the on-ramp for hobby projects almost frictionless. They also operate a top-staked validator, which gives them more leverage on transaction landing than most.&lt;/p&gt;

&lt;p&gt;The tradeoff worth flagging: the Enhanced APIs are useful but sticky. Once your code is wired to "give me a parsed transaction with token transfers labeled," moving to another provider means writing the parser yourself. That's not a knock on their engineering. It's a portability choice worth making consciously.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. GetBlock
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gif2hyhxny1mq5mn0fy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gif2hyhxny1mq5mn0fy.png" alt="GetBlock Website" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GetBlock benchmarks #1 on raw latency in Asia, EU, and Africa, which is credible for users outside North America. Their dedicated nodes ship with Yellowstone gRPC included rather than as an add-on, unusual at their price point, and they offer a LandFirst transaction submission product that competes with paid SWQoS tiers elsewhere.&lt;/p&gt;

&lt;p&gt;Their shared tier is fine for hobby projects but they're at their best as a regional dedicated provider. They also offer free engineering help for custom configurations, worth mentioning not as praise but as a signal of where they sit. You're getting hands-on attention you wouldn't get from QuickNode or Alchemy at the same spend.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. RPC Fast
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F412noginhwuvc3q3g7ov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F412noginhwuvc3q3g7ov.png" alt="RPC Fast Website" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RPC Fast is the most opinionated provider on this list. They run bare-metal dedicated nodes only, ship Jito ShredStream on by default, and price everything custom. The pitch is straightforward: HFT-grade infrastructure for teams that can write a procurement email.&lt;/p&gt;

&lt;p&gt;Their automated failover claim of sub-50ms recovery is aggressive enough that it's worth pressure-testing in a real benchmark before signing anything, but the underlying setup (bare-metal nodes, geographic redundancy) is the right shape for it. Yellowstone gRPC is supported but not their primary streaming pitch. ShredStream is.&lt;/p&gt;

&lt;p&gt;The catch is the pricing model. Custom-only is fine when the budget exists; it's a wall when the goal is to spin up a node over the weekend. Skip this one if "request a quote" isn't a workflow you can run.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Alchemy
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9k2kt80mdokgq5tvuv7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9k2kt80mdokgq5tvuv7.png" alt="Alchemy Website" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alchemy supports 37+ chains and has the deepest developer tooling in crypto, the kind of metering, logging, replay, and trace infrastructure you'd expect from a much older industry. For teams already using them on EVM, adding Solana is two clicks and a billing change.&lt;/p&gt;

&lt;p&gt;What you get: solid latency (40-60ms observed in North America and Asia), a generous free tier (30M compute units a month), and the most polished docs on this list. What you don't get: Solana-specific depth. There's no equivalent of Helius's parsed APIs, no Jetstream-style shred feed, and the highest shared plan caps at 300 RPS.&lt;/p&gt;

&lt;p&gt;Alchemy is the right answer when Solana is one of several chains being supported and managing two relationships isn't appealing. It's not the right answer when Solana is the hot path.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. QuickNode
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w8aifo98njr7a2rkuh7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w8aifo98njr7a2rkuh7.png" alt="QuickNode Website" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;QuickNode is the EC2 of crypto RPC. They support 75+ chains across 120+ networks, have the most polished dashboard in the space, and offer a long shelf of add-ons to compose per-project. MEV protection, transaction speed boosters, NFT and token APIs, Yellowstone gRPC on port 10000, and so on.&lt;/p&gt;

&lt;p&gt;For multi-chain teams, especially ones that want a single vendor for both EVM and Solana, QuickNode is the pragmatic answer. Their ops are mature, their SLAs are real, and their support is responsive in ways most of this list isn't.&lt;/p&gt;

&lt;p&gt;Where they're not the obvious pick: pure Solana work where every dial needs to be turned up. Standard tiers cap shared throughput around 400 RPS, which sounds like plenty until a sniper is fanning blockhash refreshes through a launch. The Solana-specific depth, parsed APIs, shred-level feeds, fine-grained staked submission, is shallower than what Helius, Triton, or OrbitFlare offer.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Ankr
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl766jifa66gl6jgzs9e0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl766jifa66gl6jgzs9e0.png" alt="Ankr Website" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ankr runs a decentralized RPC network across 80+ chains, with throughput up to ~1,500 RPS on premium tiers. Pricing is pay-as-you-go from around $6 per 1M requests, which is the most cost-effective option on this list for low-volume reads.&lt;/p&gt;

&lt;p&gt;Two things to know. Their network model means there's no single dedicated machine, traffic is load-balanced across operators. That's fine for read-heavy workloads, less ideal when predictable latency for transaction submission is a requirement. SWQoS access is gated behind their premium tier.&lt;/p&gt;

&lt;p&gt;Pick Ankr when cost per read matters more than tail latency. Skip it for any hot path.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Chainstack
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0xjbwm865n9hy7v6swg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0xjbwm865n9hy7v6swg.png" alt="Chainstack Website" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chainstack quietly turned on Jito ShredStream by default on their Solana nodes in early 2026, shipped a Trader Node product with priority routing, and run real SOC 2 Type II compliance, which matters more than people admit when the goal is to onboard institutional customers.&lt;/p&gt;

&lt;p&gt;Their Unlimited Node tier at $149/mo is the best flat-rate offer in the market. Full RPC, WebSocket, and gRPC access without the per-request metering that turns other providers' pricing pages into spreadsheet exercises. That directly undercuts OrbitFlare's Growth tier on raw monthly cost. Chainstack sits below the providers above in this ranking because their Solana product is one of many things they offer rather than their entire business. For teams already on Chainstack for EVM work, extending to Solana is a one-tab decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Syndica
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fasswm56z18cnx3rcoycp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fasswm56z18cnx3rcoycp.png" alt="Syndica Website" width="799" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Syndica is Solana-only and has leaned hard into observability. ChainStream gives a query layer over historical Solana data. Their dashboards show what RPC traffic actually looks like, with request mix, p99 latency by method, and error rates broken down in a way most providers don't bother with.&lt;/p&gt;

&lt;p&gt;The core RPC is solid but isn't differentiated on raw speed. The reason to pick Syndica is the diagnostics. When a team is trying to figure out why a particular method is slow, or which addresses are eating most of their getAccountInfo budget, having that data already collected beats writing a metrics pipeline from scratch.&lt;/p&gt;

&lt;p&gt;Best fit for teams with their hands full of Solana-specific debugging and a real need to understand their own usage in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dedicated vs Shared
&lt;/h2&gt;

&lt;p&gt;A quick note, because people still ask this every week.&lt;/p&gt;

&lt;p&gt;Shared nodes get you started faster and cost less, but they come with noisy-neighbor effects. When another tenant runs a heavy &lt;code&gt;getProgramAccounts&lt;/code&gt; query on the same instance, p99 latency spikes. On the better providers this is minor. On cheaper ones it can be severe.&lt;/p&gt;

&lt;p&gt;Dedicated nodes remove the noise but introduce configuration and capacity questions that used to be the provider's problem. You pick the region. You pick the hardware tier. You pay whether your traffic is full or empty.&lt;/p&gt;

&lt;p&gt;The right answer depends more on predictability requirements than on scale. A small trading operation that needs consistent latency belongs on dedicated before a much larger read-heavy app that can tolerate occasional spikes. Every major provider on this list offers both shapes. Pick the one that matches what you need to be certain about.&lt;/p&gt;

&lt;h2&gt;
  
  
  By Use Case
&lt;/h2&gt;

&lt;p&gt;The honest mapping, since "no universal winner" sounds wise but doesn't help anyone make a decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trading, MEV, sniping.&lt;/strong&gt; OrbitFlare, Triton One, or RPC Fast. All three give shred-level or sub-block feeds and serious latency. OrbitFlare for teams that want one SDK across the whole transport surface. Triton if the team is already built around Yellowstone and the institutional reputation is part of the buying decision. RPC Fast if the budget is open and procurement is an option.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solana-native dApps with NFT or token surfaces.&lt;/strong&gt; Helius. The Enhanced Transactions API and DAS will save weeks of indexer work. Plan for the portability cost when moving.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-chain teams.&lt;/strong&gt; QuickNode for breadth and ops maturity, Alchemy for developer tooling depth, Chainstack for the flat-rate pricing. The right answer depends on existing relationships more than the technology.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Institutional workloads with compliance requirements.&lt;/strong&gt; Chainstack (SOC 2 Type II) or Triton One. Helius is also SOC 2 certified but fewer of their enterprise customers talk about it publicly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost-sensitive read workloads.&lt;/strong&gt; Ankr. Pay-as-you-go pricing is the cheapest cost-per-request on this list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solana with regional concentration outside North America.&lt;/strong&gt; GetBlock for Africa benchmarks. OrbitFlare for any of the 11 regions across the US, Europe (including Eastern Europe via Siauliai), and Asia (Tokyo and Singapore).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production debugging on Solana.&lt;/strong&gt; Syndica's observability layer earns its rank.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  At a Glance
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztw17i5htdzbryd00alk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztw17i5htdzbryd00alk.png" alt="Providers Comparison" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Floor
&lt;/h2&gt;

&lt;p&gt;There is no universal best. There is a worst, though, and that's running anything you care about on a public RPC endpoint and being surprised when it stops responding the moment a launch hits. Pick something on this list. The cheapest paid tier of any of them beats free.&lt;/p&gt;

&lt;p&gt;To compare specifics against OrbitFlare, or to get help sizing the right tier for a workload, &lt;a href="//discord.gg/orbitflare"&gt;get in touch&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>orbitflare</category>
      <category>rpc</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>The OrbitFlare SDK: One Rust Crate for Every Solana Transport</title>
      <dc:creator>OrbitFlare RPC</dc:creator>
      <pubDate>Sun, 26 Apr 2026 15:38:00 +0000</pubDate>
      <link>https://dev.to/orbitflarerpc/the-orbitflare-sdk-one-rust-crate-for-every-solana-transport-4doi</link>
      <guid>https://dev.to/orbitflarerpc/the-orbitflare-sdk-one-rust-crate-for-every-solana-transport-4doi</guid>
      <description>&lt;p&gt;Building a Solana app in Rust tends to mean you collect SDKs. One for JSON-RPC because you need &lt;code&gt;get_balance&lt;/code&gt; and &lt;code&gt;get_transaction&lt;/code&gt; for the obvious one-shot reads. One for WebSocket because polling for account changes gets tired fast. One for gRPC because Yellowstone is the only realistic way to keep up once your volume passes a certain threshold. And often a fourth for whatever specialized feed you've signed up for on top of it, because the first three stop being enough the moment latency starts mattering to your app.&lt;/p&gt;

&lt;p&gt;Each one arrives with its own types, its own error model, its own opinions about how to reconnect when the socket drops, and its own way of threading auth into a URL. You end up writing the same wrapper code in four slightly different places - retry the request, fall back to a secondary endpoint, redact the api key out of log lines, time out when the connection has gone silent - and none of it is the reason you started the project. It's the least interesting code in any Solana app, and somehow it ends up being the most fragile too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The OrbitFlare Rust SDK
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fax0qd676hzajoix8gxek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fax0qd676hzajoix8gxek.png" alt="OrbitFlare homepage"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://orbitflare.com" rel="noopener noreferrer"&gt;OrbitFlare&lt;/a&gt;&lt;/strong&gt; sits at the other end of that problem. We run Solana RPC, WebSocket, and gRPC endpoints, plus our own Jetstream feed for the cases where Geyser-based streams can't keep up.&lt;/p&gt;

&lt;p&gt;Our new Rust SDK is what you use to talk to any of it, and it's shaped around a single builder pattern and a single error type across every transport, so the code you write to call &lt;code&gt;get_balance&lt;/code&gt; over HTTP reads almost identically to the code you write to open a binary gRPC firehose.&lt;/p&gt;

&lt;p&gt;What that buys you, beyond a shorter &lt;code&gt;Cargo.toml&lt;/code&gt;, is that all the plumbing you would otherwise be writing per-client lives once, in one place, and gets better over time instead of drifting in four directions at once.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Transports
&lt;/h2&gt;

&lt;p&gt;The crate exposes four transport modules, each behind its own feature flag.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;rpc&lt;/code&gt; is the typed JSON-RPC client you'll reach for whenever you need a one-shot read, a transaction submission, or a historical lookup.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RpcClientBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://ams.rpc.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;ws&lt;/code&gt; gives you the pub/sub surface for the things you want to watch as they happen on-chain: slots, accounts, signatures, and log filters.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;WsClientBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ws://ams.rpc.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;grpc&lt;/code&gt; is the Yellowstone-compatible firehose, where you open one long-lived subscription, hand the server a set of filters, and let it stream every matching event straight from the validator's Geyser plugin.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;geyser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;GeyserClientBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://ams.rpc.orbitflare.com:10000"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;jetstream&lt;/code&gt; has the same API shape as the gRPC client, but the data comes out of our own shred-decoded pipeline rather than Geyser, which is a meaningful win when "earlier" matters to what you're building.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;jetstream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;JetstreamClientBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://ams.jetstream.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo add orbitflare-sdk &lt;span class="nt"&gt;--features&lt;/span&gt; &amp;lt;features&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The available features are &lt;code&gt;rpc&lt;/code&gt;, &lt;code&gt;ws&lt;/code&gt;, &lt;code&gt;grpc&lt;/code&gt;, and &lt;code&gt;jetstream&lt;/code&gt;. Pick whichever combination your app actually needs and your dependency tree stays lean.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Don't Have to Write
&lt;/h2&gt;

&lt;p&gt;The boring infrastructure around any transport client - reconnect, fallback, liveness, api key handling - is where most of the bugs in any Solana app quietly live, and it's fundamentally the same work regardless of which protocol you're speaking. &lt;/p&gt;

&lt;p&gt;The SDK handles it once, on your behalf, and runs the same implementation across every client. When a socket drops, the subscriptions you had on it get re-registered against the new connection. When a primary endpoint starts misbehaving, the client backs off and cycles through whatever fallback URLs you chained onto the builder, bringing the primary back into rotation once it recovers. &lt;/p&gt;

&lt;p&gt;And anywhere a URL might end up in an error log, the api key gets redacted out of it first and you start grepping your tracing output.&lt;/p&gt;

&lt;h2&gt;
  
  
  In a Real Project
&lt;/h2&gt;

&lt;p&gt;Most apps built on the SDK end up with roughly the same shape. You construct the clients you need up front, hand them off to whichever parts of the app are going to use them, and let the SDK manage the underlying connections for the lifetime of the process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;orbitflare_sdk&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;
    &lt;span class="n"&gt;GeyserClientBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RpcClientBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WsClientBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RpcClientBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://ams.rpc.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;WsClientBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.urls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s"&gt;"ws://ams.rpc.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"ws://lon.rpc.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;geyser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;GeyserClientBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://ams.rpc.orbitflare.com:10000"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// ... use rpc, ws, geyser&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The demo we're going to build over the rest of this post is a small wallet ticker. You pass in a pubkey at the command line, and the program prints a live view of that wallet's SOL balance along with every token account it owns, updating the display in place as the balances change. Around 120 lines of code end to end.&lt;/p&gt;

&lt;p&gt;It uses the same pattern the code sketch above hinted at. The RPC client handles the bootstrap - one &lt;code&gt;get_balance&lt;/code&gt; for the SOL side, one &lt;code&gt;get_token_accounts_by_owner&lt;/code&gt; for the SPL tokens, and a handful of small lookups to decorate each account with its mint's decimals so the output reads as token amounts rather than raw integers. &lt;/p&gt;

&lt;p&gt;From there the WebSocket client takes over: we open an &lt;code&gt;account_subscribe&lt;/code&gt; for the wallet itself and one for each token account we found, merge the updates into a single stream inside the app, and redraw the dashboard whenever any of them tick. The RPC client gets you the starting state; the WebSocket client keeps it honest from there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up the Project
&lt;/h3&gt;

&lt;p&gt;Create a new Cargo project and pull in the dependencies you'll need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[package]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"wallet-ticker"&lt;/span&gt;
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.0"&lt;/span&gt;
&lt;span class="py"&gt;edition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2024"&lt;/span&gt;
&lt;span class="py"&gt;rust-version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.85"&lt;/span&gt;

&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;orbitflare-sdk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"rpc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ws"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;tokio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.52.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"full"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;serde_json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.149"&lt;/span&gt;
&lt;span class="py"&gt;base64&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.22.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;orbitflare-sdk&lt;/code&gt; with the &lt;code&gt;rpc&lt;/code&gt; and &lt;code&gt;ws&lt;/code&gt; features gives you exactly the two transports this project uses and nothing else. &lt;/p&gt;

&lt;p&gt;Tokio's &lt;code&gt;full&lt;/code&gt; feature is convenient for a tutorial; in a production app you'd bare that down to the runtime pieces you actually rely on. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;base64&lt;/code&gt; and &lt;code&gt;serde_json&lt;/code&gt; show up because WebSocket account updates arrive as base64-encoded bytes wrapped in a JSON envelope, and you'll be reaching into both.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the Clients
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;RpcClient::build&lt;/code&gt; is synchronous; &lt;code&gt;WsClient::build&lt;/code&gt; is async because it actually opens the socket. The &lt;code&gt;Arc&lt;/code&gt; wrap on &lt;code&gt;ws&lt;/code&gt; is there because each subscription will live in its own &lt;code&gt;tokio::spawn&lt;/code&gt; and they all need to reach the same underlying connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RpcClientBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://ams.rpc.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.commitment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"confirmed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nn"&gt;WsClientBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ws://ams.rpc.orbitflare.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Bootstrap
&lt;/h3&gt;

&lt;p&gt;Pulling the wallet's current state is two RPC calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;sol_lamports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;&lt;span class="nf"&gt;.get_balance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;raw_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rpc&lt;/span&gt;
    &lt;span class="nf"&gt;.get_token_accounts_by_owner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;get_token_accounts_by_owner&lt;/code&gt; returns each entry in &lt;code&gt;jsonParsed&lt;/code&gt; encoding, so the mint address, token amount, and decimals are already structured fields you can lift straight into a &lt;code&gt;HashMap&amp;lt;pubkey, Holding&amp;gt;&lt;/code&gt;. The pubkey you key by is the token account's own address - that's the id you'll subscribe to in the next step, not the mint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Subscribing Concurrently
&lt;/h3&gt;

&lt;p&gt;Once you have the list of accounts, you need one subscription for the wallet itself and one per token account. The shape that works is a &lt;code&gt;tokio::spawn&lt;/code&gt; per subscription sharing an &lt;code&gt;Arc&amp;lt;WsClient&amp;gt;&lt;/code&gt;, with all of them pushing updates into a single &lt;code&gt;mpsc&lt;/code&gt; channel the main loop drains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;rx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;mpsc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pubkey&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;holdings&lt;/span&gt;&lt;span class="nf"&gt;.keys&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.cloned&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nn"&gt;tokio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="nf"&gt;.account_subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"confirmed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="nf"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// decode v["data"][0] as an SPL token account,&lt;/span&gt;
            &lt;span class="c1"&gt;// then send an Update down tx&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;tokio::spawn&lt;/code&gt; is what makes this scale. A naive &lt;code&gt;for pubkey in ... { ws.account_subscribe(...).await? }&lt;/code&gt; loop works too, but it serializes one subscribe per round-trip. That's fine for a dozen accounts, painful for a few hundred, and flat-out unusable on wallets with thousands of token accounts. Spawning lets every subscription open in parallel, and the first updates start landing in the channel before the last subscribe ack even comes back.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Render Loop
&lt;/h3&gt;

&lt;p&gt;Everything comes together in a short loop that reads the next update, mutates local state, and redraws:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rx&lt;/span&gt;&lt;span class="nf"&gt;.recv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Sol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lamports&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sol_lamports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lamports&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;holdings&lt;/span&gt;&lt;span class="nf"&gt;.get_mut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="py"&gt;.amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sol_lamports&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;holdings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it against any Solana address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ORBITFLARE_LICENSE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ORBIT-KKKKKK-EEEEEE-YYYYYY cargo run &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &amp;lt;pubkey&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see the dashboard populate within a few hundred milliseconds as the RPC bootstrap lands, then each line ticks in place the moment something touches the wallet on-chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wallet: CKs1E69a2e9TmH4mKKLrXFF8kD3ZnwKjoEuXa6sz9WqX

  SOL     0.040420950
  EPjF...Dt1v      42.500000
  So11...1112       0.005000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ctrl+C to quit. The full source - about 140 lines of Rust end to end, including the &lt;code&gt;render&lt;/code&gt; function, the state types, and the bootstrap parse loop - is linked at the bottom of the post.&lt;/p&gt;

&lt;p&gt;That's about it for the SDK in broad strokes - a builder per transport, a shared error and retry story, and the reconnect and fallback work kept inside the crate where you don't have to think about it. &lt;/p&gt;

&lt;p&gt;The ticker above is the smallest app that meaningfully exercises more than one of the clients at a time, but the shape scales up from there: the same pattern works just as well when you're stitching together a copy trader, a liquidation monitor, or anything else that needs to move between one-shot reads and live streams in the same loop.&lt;/p&gt;

&lt;p&gt;With the SDK in place, the plumbing is off your plate and what's left is the part of the project that's actually yours to build. Which, for most of us, is the only reason we started one in the first place.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://crates.io/crates/orbitflare-sdk" rel="noopener noreferrer"&gt;&lt;code&gt;orbitflare-sdk&lt;/code&gt; on crates.io&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/orbitflare/wallet-ticker" rel="noopener noreferrer"&gt;Full Wallet Ticker Project&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/orbitflare/orbitflare-sdk-rs/tree/main/crates/orbitflare-sdk/examples" rel="noopener noreferrer"&gt;SDK Examples on GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.orbitflare.com/sdk/overview" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you build something with the crate, or run into a rough edge that should be smoother, we'd love to &lt;em&gt;&lt;a href="//discord.gg/orbtiflare"&gt;hear&lt;/a&gt;&lt;/em&gt; about it and help you out!&lt;/p&gt;

</description>
      <category>solana</category>
      <category>sdk</category>
      <category>rust</category>
      <category>orbitflare</category>
    </item>
  </channel>
</rss>
