SWQoS vs Jito vs a Relay: Which Solana Sender to Use
What SWQoS and staked connections are, how Jito bundles and tips work, what a relay adds, and which Solana sender fits each case. With Node.js code.
Ask how Solana traders "send fast" and you'll hear three answers: SWQoS, Jito, a relay. They aren't three versions of one thing. SWQoS is a rule inside the leader's validator, Jito is a separate auction for bundles, and a relay is a service that pushes your signed transaction down several paths, often including the other two.
This post explains each, how they fit together and which to use when, with Node.js code at the end.
Disclosure: AllenHark runs AllenHark Relay, one of the senders compared here. Facts about other senders come from their own docs, linked, checked 31 October 2026.
The short answer
| SWQoS | Jito | A relay (sender) | |
|---|---|---|---|
| What it is | How a leader shares out its QUIC connection and stream capacity, by the sender's stake | An off-chain Block Engine that auctions bundles to leaders running a Jito client | A service that takes your signed transaction and sends it down several paths at once |
| Who can use it | Nodes whose identity key has stake, and the RPC nodes and senders they peer with | Anyone, directly or through a relay | Anyone; most need an API key |
| What it costs, in principle | Nothing on-chain; you reach it through stake or a provider | A tip to a Jito tip account, set by auction, plus normal fees | Usually a tip inside each transaction, or a plan |
| Atomic? | No | Yes, for bundles of up to five transactions | Single transactions no; bundles go through Jito |
| Use it when | You don't choose it: every Agave leader applies it, so what matters is whether your path is staked | The trade is worthless unless every leg lands, in order | You want one transaction in fast, on any leader |
What are staked connections?
A staked connection is a QUIC connection to a Solana leader's transaction port (the TPU) from a node whose identity key holds stake. The leader reads that identity from the connection's TLS certificate, looks up its stake, and gives it more connections, more concurrent streams and a share of transaction capacity in proportion to the stake. Connections with no stake share a smaller pool and are throttled first when the leader is busy. That rule is stake-weighted quality of service, or SWQoS. A validator can also assign stake to a trusted peer, such as its own RPC node, with --staked-nodes-overrides, so that peer's connections count as staked too.
Your wallet's SOL balance plays no part in it. What counts is the stake behind the identity key of the machine that opens the connection.
How a transaction reaches the leader
A signed transaction can reach the current leader four ways:
- An RPC node's
sendTransaction. On Agave, the node forwards it over QUIC to the next two leaders by default, retrying every 2 seconds until it lands or its blockhash expires. It connects with the RPC node's own identity, so it is staked only if that identity is. - Straight to the leader's TPU over QUIC from your own machine: an unstaked peer, unless your identity has stake. See how to submit directly to the leader TPU.
- Jito's Block Engine, which auctions bundles to leaders running a Jito client.
- A relay, which does several of these at once.
Whichever path you use, a blockhash lasts about 150 blocks, which is about 30 seconds, and a slot is about 200 ms.
Getting in, then getting ordered
Three levers decide whether a transaction lands, and they act at different points:
| Lever | Where it acts | What it decides |
|---|---|---|
| SWQoS | The leader's QUIC server | Whether your packet gets through when the leader is busy |
| Priority fee | The leader's scheduler | Where your transaction sits in the queue once it is inside |
| Jito tip | Jito's Block Engine auction | Which bundles the Block Engine hands to a Jito leader |
A priority fee raises the chance that the leader schedules your transaction ahead of competing ones; Agave ranks transactions by fee income per unit of estimated cost. But the scheduler only sees what got through the QUIC server, so no priority fee helps a packet that was throttled at the door. That's one reason transactions arrive late even with priority fees.
SWQoS in detail
Solana's guide sums up the idea with an example: a validator with 0.5% of the stake may send up to 0.5% of the packets the leader takes in. The details live in Agave's streamer code.
What the leader does
When a QUIC connection opens, the leader takes the public key from the peer's TLS certificate and looks up its stake, with any --staked-nodes-overrides entry taking precedence. These are the defaults in Agave 4.4.0, released 28 October 2026:
| Staked peer | Unstaked peer | |
|---|---|---|
| Connection slots on the leader | 2,000; when full, a new peer can evict a randomly sampled peer with less stake | 3,000; when full, the oldest are pruned |
| Connections per peer | 16 | 8 |
| Concurrent streams per connection | 128 to 512, scaled by stake | 128 |
| Transactions a second per peer | Up to the leader's whole capacity until staked load passes 76% of it, then a share in proportion to stake, never below 210 | 400 a second, cut to 100 once total load passes 70% of capacity |
Two more rules: a peer with less than 1/50,000 of total stake counts as unstaked, and unstaked traffic never throttles staked peers. Agave 4.3 instead set aside 80% of stream capacity for staked peers, the figure in Solana's guide, and capped each unstaked peer at 200 transactions a second. Validators running Firedancer use separate code.
How an RPC node gets it
Per Solana's guide, a validator with stake lists the RPC node's identity in its --staked-nodes-overrides file, and the RPC node sends to that validator's QUIC TPU port with --rpc-send-transaction-tpu-peer HOST:PORT, the "peer(s) to broadcast transactions to instead of the current leader" in Agave's help text. Such agreements "must be made directly between RPC operators and Validators", and the guide warns validators against doing this for untrusted RPC nodes.
An override changes how that one validator treats you. Every other leader looks at the stake behind your connection's identity.
Why you can't buy SWQoS for your bot
- Your wallet doesn't count. SWQoS keys on the identity that opens the QUIC connection, not the wallet that signs the transaction.
- Staking your SOL doesn't help your bot. Delegated stake belongs to the validator. Solana's guide says it is "not necessary, recommended or effective to delegate stake to RPC servers".
- A little stake isn't enough. Below 1/50,000 of total stake, Agave treats you as unstaked.
So you get SWQoS by running a staked validator, or by sending through a provider whose connections are staked. Most senders below sell exactly that.
Jito in detail
Validators running Jito-Solana, a modified Agave client, connect to Jito's Block Engine. Traders and bots send it transactions and bundles; it simulates them, runs an auction and passes the winners to the validator. Tips go to validators and their stakers.
- Bundles: up to five transactions, run in order and atomically within one slot, or not at all. The tip is any instruction, top-level or inside a program call, that sends SOL to one of eight tip accounts; Jito warns against putting tip accounts in address lookup tables.
- The auction: bundles compete on tip, in parallel auctions for bundles that touch different accounts.
sendBundlevssendTransaction: withsendBundle, "only the Jito tip matters".sendTransactionforwards one transaction to the validator with MEV protection; withbundleOnly=trueit goes as a one-transaction bundle with revert protection. ForsendTransaction, Jito suggests a 70/30 split between priority fee and tip.- Only Jito leaders count: "Tips do not prioritize transactions for validators that are not Jito-Solana leaders." Not every leader runs a Jito client, so a bundle can wait several slots for one, or expire with its blockhash.
- Skipped blocks: Jito warns that if a block holding your bundle is skipped, its transactions can be rebroadcast and land one by one, outside the bundle rules. Guard with checks on account state before and after.
- Limits: 1 request per second per IP per region by default, with no auth key needed.
Jito's newer BAM (Block Assembly Marketplace) hands scheduling to a BAM Node that sequences transactions and Jito bundles for connected validators; per its docs, even transactions sent straight to a BAM validator's TPU go through BAM before execution. bam.dev has its current state. For tips and failures, see how to send Jito bundles and the Jito bundles guide.
What a relay adds
A relay, or sender, takes your signed transaction and sends it down several paths at once: staked QUIC, direct QUIC and UDP to upcoming leaders, RPC nodes, and block builders such as Jito. If its connections are staked, you get SWQoS without stake of your own, and one request reaches Jito and non-Jito leaders alike.
The senders below charge a tip: a SOL transfer to their tip account inside your transaction, which moves only if the transaction lands and succeeds. Bundles aren't fanned out: split into separate transactions, a bundle would lose its atomicity, so a relay sends it to Jito whole.
AllenHark Relay sends each transaction through five channels at once: stake-weighted QUIC, QUIC and UDP to the leaders, an RPC fan-out, and the Jito Block Engine with other relayers. It lands transactions in the same block, at 0.1 ms over QUIC, and also takes WebSocket and HTTPS. Bundles of up to five go to the Jito Block Engine only, with a Jito tip on top. Each key gets 10 requests per second by default, more on request, and Relay Dedicated, a monthly add-on, lets whitelisted wallets send with no relay tip. It is the service first sold as 0-slot, not the 0slot (0slot.trade) below. Slipstream is a separate AllenHark product: a sender-agnostic relay that routes through the worker nearest the current leader, with 0.2 ms leader RTT.
Senders compared
How we compared: each row says what the sender's own docs say about how it sends and how you pay, checked 31 October 2026. We didn't benchmark landing rates or latency, and we list no prices or tip amounts: follow the links for current figures.
| Sender | How it sends, per its docs | How you pay |
|---|---|---|
| AllenHark Relay | Five channels at once, including stake-weighted QUIC and the Jito Block Engine; bundles go to Jito only | A tip inside each transaction to an AllenHark tip wallet, or Relay Dedicated |
| Helius Sender | Sender Max uses all its pathways at once (Helius, Jito, Harmonic, Rakurai and others); the SWQOS-only tier takes a single fast path; sendBundle takes up to four transactions | A tip to a designated tip account plus a required priority fee in every transaction; no API credits |
| Nozomi (Temporal) | Block builders (Jito, Harmonic) and Nozomi's staked connections; orders what it holds by tip and retries until confirmed or the blockhash expires | A tip to a Nozomi tip address, paid only when the transaction lands |
| 0slot | A staked_conn sendTransaction that "directly connects to our validator node", with dedicated SWQoS per user | A tip to a 0slot tip account in each transaction, on plans sized by transactions per second |
| bloXroute Trader API | submit with options for staked connections (useStakedRPCs), leader-risk scoring that delays or skips risky leaders (frontRunningProtection), or revert protection, which sends to the Jito Block Engine and Paladin leaders only | A tip to a bloXroute tipping address in every transaction, plus a Trader API subscription |
| Jito Block Engine, direct | sendTransaction and sendBundle; bundles land only with Jito-client leaders | A tip to a Jito tip account, set by auction |
Sources: AllenHark Relay docs; Helius Sender; Nozomi tipping and submission; 0slot docs and home page; bloXroute submit, tipping and landing modes; Jito low-latency send. Checked 31 October 2026.
Which sender to use
One fast swap
A snipe, an exit, any single swap that must land now: use a relay. One request covers staked connections, Jito leaders and the rest, for one tip. Send over QUIC when milliseconds count, and keep a priority fee: off the block-builder paths, the leader's scheduler orders by fee. More in the fastest way to land Solana transactions.
An atomic multi-leg trade
Arbitrage, or setup plus trade plus cleanup, where leg two is worthless without leg one: use a Jito bundle, directly or through a relay. With AllenHark Relay that means two tips, the relay's and Jito's. Expect to wait for a Jito leader, and re-sign with a fresh blockhash if the bundle expires. If the legs fit in one transaction, that is atomic on every leader: see DEX arbitrage in one transaction.
You run your own staked validator
Your validator's identity already has stake, so the connections it opens are staked. To give your own RPC node or sender the same treatment, follow Solana's peering setup with --staked-nodes-overrides and --rpc-send-transaction-tpu-peer. For bundles you still need Jito, directly or through a relay.
Low-volume, not urgent
Payments, claims, transfers that can wait a few seconds: a reliable RPC's sendTransaction with a sensible priority fee is enough, with no tips. AllenHark RPC gives 100 requests per second on the standard plan, and Dedicated RPC has no rate limits.
A bot sending through several senders at once
Each sender wants its own tip inside the transaction. One transaction carrying every tip pays them all when it lands; separate copies with one tip each and the same blockhash can land more than once: two buys, two tips.
The fix is a durable nonce. Every copy uses the same nonce value in place of a recent blockhash. The first copy processed advances the nonce; any other copy then fails the nonce check, and per Solana's docs "the entire transaction is dropped. No fees collected, no state changes." At most one copy lands, and one tip is paid. AllenHark's managed bots do this for you: they send through AllenHark Relay by default, Advanced mode adds your own Nozomi, 0slot, Jito and Helius Sender accounts, and with two or more senders on, each sender gets its own copy (Fast senders).
Two caveats: Nozomi's docs warn that block builders may deprioritize durable-nonce transactions, which are associated with spam, and Solana's docs say durable nonces may be deprecated in a future release.
Code: send one transaction through AllenHark Relay
This script builds a transaction with a compute-unit price, a stand-in for your swap (1 lamport to yourself) and the relay tip, signs it, posts it to AllenHark Relay's HTTPS endpoint and polls until it lands, printing the send slot and the landing slot.
The relay checks the tip first: a top-level SystemProgram.transfer to one of its tip wallets, with the destination in the static account keys, not behind a lookup table. The minimum is in the relay docs. The script reads the tip from RELAY_TIP_LAMPORTS and the key file's path from KEYPAIR; nothing is hard-coded.
// send-via-relay.mjs: build one transaction with a priority fee and a relay tip,
// send it through AllenHark Relay over HTTPS, and report the slot it landed in.
// npm i @solana/web3.js@1 (Node 18 or later, for fetch)
import fs from "node:fs";
import {
ComputeBudgetProgram,
Connection,
Keypair,
PublicKey,
SystemProgram,
TransactionMessage,
VersionedTransaction,
} from "@solana/web3.js";
const RPC_URL = process.env.RPC_URL ?? "https://api.mainnet.solana.com";
const RELAY_URL = process.env.RELAY_URL ?? "https://relay.allenhark.com/v1/sendTx";
const API_KEY = process.env.RELAY_API_KEY; // from the Relay tab of your console
const TIP_LAMPORTS = Number(process.env.RELAY_TIP_LAMPORTS); // at least the minimum in the relay docs
if (!API_KEY || !process.env.KEYPAIR || !(TIP_LAMPORTS > 0)) {
throw new Error("Set RELAY_API_KEY, KEYPAIR (path to a keypair JSON file) and RELAY_TIP_LAMPORTS");
}
// AllenHark tip wallets, from the relay docs. Pick one at random for each transaction.
const TIP_WALLETS = [
"hark1zxc5Rz3K8Kquz79WPWFEgNCFeJnsMJ16f22uNP",
"harkm2BTWxZuszoNpZnfe84jRbQTg6KGHaQBmWzDGQQ",
"hark4CwtTnN2y9FaxjcFBAJdJqQrpouu5pgEixfqdEz",
"harkoJfnM6dxrJydx5eVmDVwAgwC94KbhuxF69UbXwP",
"hark6hUDUTekc1DGxWdJcuyDZwf6pJdCxd4SXAVtta6",
"harkoTvFpKSrEQduYrNHXCurARVT19Ud3BnFhVxabos",
"harkEpXoJv5qVzHaN7HSuUAd6PHjyMcFMcDYBMDJCEQ",
"harkyXDdZSoJGyCxa24t2QXx1poPyp8YfghbtpzGSzK",
"harkR2YJ4Dpt4UDJTcBirjnSPBhNpQFcoFkNpCkVqNk",
"harkRBygM8pHYe4K8eBjfxyEX19oJn3LepFjvNbLbyi",
"harkYFxB6DuUFNwDLvA5CQ66KpfRvFgUoVypMagNcmd",
];
const payer = Keypair.fromSecretKey(
Uint8Array.from(JSON.parse(fs.readFileSync(process.env.KEYPAIR, "utf8"))),
);
const connection = new Connection(RPC_URL, "confirmed");
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
// Priority fee in micro-lamports per compute unit: the 75th percentile of recent
// fees on the accounts the transaction writes. For a real swap, pass the pool accounts.
async function computeUnitPrice(writable) {
const fees = (await connection.getRecentPrioritizationFees({ lockedWritableAccounts: writable }))
.map((f) => f.prioritizationFee)
.sort((a, b) => a - b);
return Math.max(1, fees[Math.floor(fees.length * 0.75)] ?? 0);
}
const tipWallet = new PublicKey(TIP_WALLETS[Math.floor(Math.random() * TIP_WALLETS.length)]);
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
const instructions = [
ComputeBudgetProgram.setComputeUnitLimit({ units: 10_000 }),
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: await computeUnitPrice([payer.publicKey]) }),
// Stand-in for your swap: move 1 lamport to yourself.
SystemProgram.transfer({ fromPubkey: payer.publicKey, toPubkey: payer.publicKey, lamports: 1 }),
// The relay tip: a top-level transfer whose destination sits in the static account
// keys. No lookup table is used, so it does.
SystemProgram.transfer({ fromPubkey: payer.publicKey, toPubkey: tipWallet, lamports: TIP_LAMPORTS }),
];
const tx = new VersionedTransaction(
new TransactionMessage({ payerKey: payer.publicKey, recentBlockhash: blockhash, instructions }).compileToV0Message(),
);
tx.sign([payer]);
const sentSlot = await connection.getSlot("processed");
const res = await fetch(RELAY_URL, {
method: "POST",
headers: { "Content-Type": "application/json", "x-api-key": API_KEY },
body: JSON.stringify({ tx: Buffer.from(tx.serialize()).toString("base64"), simulate: false }),
});
const reply = await res.json();
if (reply.status !== "accepted") throw new Error(`Relay rejected it: ${reply.error ?? res.status}`);
console.log(`accepted ${reply.signature}, sent at slot ${sentSlot}`);
// Accepted is not landed. Poll until it is confirmed or its blockhash expires.
for (let i = 0; ; i++) {
const [status] = (await connection.getSignatureStatuses([reply.signature])).value;
if (status && (status.confirmationStatus === "confirmed" || status.confirmationStatus === "finalized")) {
const outcome = status.err ? `failed: ${JSON.stringify(status.err)}` : "succeeded";
console.log(`landed in slot ${status.slot} (${status.slot - sentSlot} after the send slot), ${outcome}`);
break;
}
if (i % 5 === 4 && (await connection.getBlockHeight("confirmed")) > lastValidBlockHeight) {
console.log("blockhash expired before it landed: rebuild with a fresh blockhash and send again");
break;
}
await sleep(200);
}Set RELAY_API_KEY, KEYPAIR and RELAY_TIP_LAMPORTS, and point RPC_URL at your own RPC; the public endpoint is rate-limited.
- The send slot is your RPC's view, which can trail the leader a little. Treat the gap as a rough measure, not a benchmark.
- Accepted is not landed. The relay answers once it has sent the transaction on; an expired blockhash, moved state or a tip too low for the congestion can still stop it.
- HTTPS is the simple path. For the lowest latency use QUIC or WebSocket; the relay docs have QUIC clients in Rust and Python.
- Bundles go to
/v1/sendBundleas atxsarray, with a Jito tip; see atomic bundles.
How we tested it: we ran the script unchanged against a local solana-test-validator, with RELAY_URL pointing at a mock of the endpoint built from the relay docs. The mock checked the x-api-key header, a body of exactly tx and simulate: false, the signature and the tip transfer, then passed the transaction to the local validator, where it landed and succeeded on three runs. The read calls also ran against mainnet's public RPC. Nothing was sent to mainnet or the real relay.
Code: one copy per sender, one tip
This builds one copy of a trade per sender, each with that sender's tip, all on one durable nonce. You need a nonce account whose authority is your trading wallet; SystemProgram.createNonceAccount makes one.
// nonce-variants.mjs: one trade, one copy per sender, at most one copy lands.
// Every copy uses the same durable nonce in place of a blockhash. The first copy
// to be processed advances the nonce; the others then fail the nonce check and are
// dropped without a fee.
import { SystemProgram, TransactionMessage, VersionedTransaction } from "@solana/web3.js";
// senders: [{ name, tipAccount: PublicKey, tipLamports }] from your own config.
// swapIxs: your compute-budget and swap instructions.
export async function buildVariants(connection, payer, noncePubkey, swapIxs, senders) {
const { nonce } = await connection.getNonce(noncePubkey, "confirmed");
return senders.map(({ name, tipAccount, tipLamports }) => {
const instructions = [
// Must be the first instruction of a durable-nonce transaction.
SystemProgram.nonceAdvance({ noncePubkey, authorizedPubkey: payer.publicKey }),
...swapIxs,
SystemProgram.transfer({ fromPubkey: payer.publicKey, toPubkey: tipAccount, lamports: tipLamports }),
];
const tx = new VersionedTransaction(
new TransactionMessage({ payerKey: payer.publicKey, recentBlockhash: nonce, instructions }).compileToV0Message(),
);
tx.sign([payer]);
return { name, tx };
});
}
// Send each copy to its own sender at the same time, then watch every signature:
// the first one to confirm is your trade, and only its tip was paid.On a local test validator we sent three copies with three different tip accounts at once. In each of three runs, one copy landed, two were dropped, one tip account was paid, and resending a dropped copy was refused. Mind the two caveats above before relying on it.
FAQ
What is SWQoS on Solana?
Stake-weighted quality of service: a leader shares out QUIC connections, streams and transaction capacity on its transaction port by the stake of the identity behind each connection. Unstaked peers share a smaller, capped pool and are throttled first.
What are staked connections?
QUIC connections to a leader from a node whose identity has stake, or has stake assigned by that validator with --staked-nodes-overrides. A sender with staked connections gets through a busy leader more often than one without.
Is Jito the same as SWQoS?
No. SWQoS is how an Agave leader admits QUIC traffic. Jito is a separate auction, and only Jito-client leaders take its bundles. A relay can use both for one transaction.
Jito or a relay: which should I use?
For one transaction that must land fast, a relay. For legs that must land together, a Jito bundle, directly or through a relay that submits bundles.
Do I still need a priority fee if I pay a tip?
Usually. The tip pays the sender or bids in Jito's auction; the priority fee orders you in the leader's scheduler on paths that aren't a block builder. Helius Sender requires both, and Jito suggests a split for sendTransaction.
Did Alpenglow change how transactions are sent?
Transaction formats, fees and execution are unchanged. The routing change Solana flags is that leaders no longer emit ticks, so a sender that timed the slot from tick counts in shreds now needs its own slot clock. See Alpenglow for RPC and gRPC users.
Related reading
- AllenHark Relay and its docs: keys, tips, endpoints and bundles.
- Jito bundles guide: tips, failures and submission.
- How to submit directly to the leader TPU.
- Why QUIC beats HTTP for transaction relay.
- Understanding Jito bundles and block building.
- Fast senders in AllenHark bots.
Sources
Checked 31 October 2026.
- Solana docs, Stake-weighted Quality of Service: the 0.5% example, the 80% figure,
--staked-nodes-overrides,--rpc-send-transaction-tpu-peer, trust and delegation advice. - Agave v4.4.0 source: streamer/src/quic.rs (connection defaults), nonblocking/swqos.rs (streams per connection, eviction, the minimum stake share), nonblocking/stream_throttle.rs (per-peer rates and load thresholds), nonblocking/quic.rs and tls_certificates.rs (identity from the TLS certificate), streamer.rs (overrides first), validator.rs (the RPC sends with the node's identity), send_transaction_service.rs and send_transaction_config.rs (two leaders, 2-second retries, the TPU peer flag). The 4.3 figures are from v4.3.2's stream_throttle.rs. Agave releases.
- Solana docs, fees and fee structure: the prioritization fee and the scheduler's priority formula.
- Solana docs, durable nonces:
AdvanceNonceAccountfirst, failure behavior, possible deprecation. - Solana Foundation, Alpenglow: ticks leave the ledger; execution, formats and fees unchanged.
- Jito, low-latency transaction send: system overview, bundles, auction, tips,
bundleOnly, rate limits, uncled blocks. - BAM, documentation.
- Helius, Nozomi, 0slot and bloXroute docs, linked under the comparison table.
- AllenHark: Relay docs, Relay, Slipstream, bot strategy and fast senders.
