<?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: Suliman Mokhtar</title>
    <description>The latest articles on DEV Community by Suliman Mokhtar (@sulimanmukhtar).</description>
    <link>https://dev.to/sulimanmukhtar</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1307777%2F32838a04-093e-419d-8f20-92bb2143ec84.jpeg</url>
      <title>DEV Community: Suliman Mokhtar</title>
      <link>https://dev.to/sulimanmukhtar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sulimanmukhtar"/>
    <language>en</language>
    <item>
      <title>How Many Confirmations Does a Solana Deposit Need?</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:30 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/how-many-confirmations-does-a-solana-deposit-need-45lh</link>
      <guid>https://dev.to/sulimanmukhtar/how-many-confirmations-does-a-solana-deposit-need-45lh</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-deposit-confirmations-how-many" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An exchange support page says your Solana deposit needs “a few confirmations”. A wallet shows a green tick after about a second. Your own explorer tab says “confirmed”, then, a while later, “finalized”. None of those three is using the word the same way, and none of them says what it counted.&lt;/p&gt;

&lt;p&gt;Solana’s commitment levels are not a count of blocks the way Bitcoin’s are. Two of them are measurements of stake, and the third is a depth. This post is what each one measures, read from the validator and the reference client, and the one deadline in the client that decides when it gives up.&lt;/p&gt;




&lt;h2&gt;
  
  
  Processed, confirmed, finalized: what each one is
&lt;/h2&gt;

&lt;p&gt;A transaction has three states the network will report.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Processed&lt;/strong&gt; means one node executed it in a block that node built or replayed. Nothing else has agreed. The block can still be abandoned, and a transaction can be “processed” and never land.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Confirmed&lt;/strong&gt; means the block reached optimistic confirmation: more than &lt;strong&gt;two-thirds of the epoch’s stake&lt;/strong&gt; has voted for it. The validator stores this as an array of 32 buckets of stake, one per lockout depth, and “confirmed” is the lowest depth at which more than two-thirds is locked out. That is a one-vote-deep supermajority. It is also the level at which a wallet turns the tick green.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Finalized&lt;/strong&gt; means the block is &lt;strong&gt;rooted&lt;/strong&gt; — the validator’s tower has 32 votes stacked on top of it, the maximum lockout history plus one. At that depth a validator can no longer vote for a competing fork without forfeiting its stake, and the reference client treats it as irreversible.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth knowing:&lt;/strong&gt; the two-thirds number is a stake fraction, not a validator count. Two hundred small validators voting is not “confirmed”; three large ones might be.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  How long each one takes, in today’s slots
&lt;/h2&gt;

&lt;p&gt;Confirmed arrives when enough stake has voted once, which in practice is a handful of slots. Finalized arrives when 32 blocks have been built on top, which is 32 slots on a healthy chain.&lt;/p&gt;

&lt;p&gt;At the 250 ms slot time in force when this was written, 32 slots is &lt;strong&gt;8 seconds&lt;/strong&gt;. The 200 ms step activated this morning and takes effect next epoch, after which it is &lt;strong&gt;6.4 seconds&lt;/strong&gt;. Under the original 400 ms slot it was 12.8 seconds, which is where most “about fifteen seconds” rules of thumb came from.&lt;/p&gt;

&lt;p&gt;Those are the best cases. A skipped leader adds its window. A fork adds the time to resolve it. And the reference client has a hard stop: if a transaction has not finalized within &lt;strong&gt;120 seconds&lt;/strong&gt;, the client gives up and reports that it may have landed on an abandoned fork.&lt;/p&gt;




&lt;h2&gt;
  
  
  The query that answers it for one block
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;getBlockCommitment&lt;/code&gt; returns the 32-bucket stake array and the total stake for a slot. The sum of buckets at depth &lt;em&gt;d&lt;/em&gt; and deeper is how much stake has that block at least &lt;em&gt;d&lt;/em&gt; votes deep. Divide by total stake and you have a number, not a word.&lt;/p&gt;

&lt;p&gt;Two limits on it. The node only keeps commitment for slots between its root and its tip, so a block that has already been rooted returns nothing — it is final; the array is gone. And the array is that node’s view: a node a few slots behind reports less stake than one at the tip.&lt;/p&gt;

&lt;p&gt;For a signature rather than a block, &lt;code&gt;getSignatureStatuses&lt;/code&gt; reports &lt;code&gt;confirmations&lt;/code&gt; as a count up to 31, and &lt;strong&gt;null once the block is rooted&lt;/strong&gt;. Null does not mean unknown. It means finalized.&lt;/p&gt;




&lt;h2&gt;
  
  
  Crediting a deposit: a rule that does not pretend
&lt;/h2&gt;

&lt;p&gt;If you credit on “confirmed”, you credit on two-thirds of stake having voted once. That has not been reorganised in practice, but it is one vote deep and the protocol does not promise it. If you credit on “finalized”, you wait 32 slots and get the protocol’s own definition of irreversible.&lt;/p&gt;

&lt;p&gt;For small amounts the difference is a few seconds; for large ones it is the difference between a measurement and a promise. The honest rule is to credit on confirmed for display and on finalized for release, and to use the stake array rather than the word when the amount justifies a query.&lt;/p&gt;

&lt;p&gt;One more thing the word hides: a transaction that never landed also never confirms, and the client will tell you nothing until its blockhash expires — 150 slots, 37.5 seconds at 250 ms and 30 seconds at 200 ms. A deposit that is “pending” past that window is not slow. It is gone, and the reasons are a separate post.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Alpenglow replaces
&lt;/h2&gt;

&lt;p&gt;Everything above is the tower-voting model. Alpenglow, active on testnet and devnet and not yet queued on mainnet when this was written, replaces vote depth with certificates: a block is final when 60% of stake has signed a finalize certificate after notarizing it, or when 80% notarizes in one round. There is no 32-block depth to wait for, and “confirmed” versus “finalized” collapses toward one event.&lt;/p&gt;

&lt;p&gt;Until the mainnet gate activates, the model in this post is the one in force. After it, the right question is “does a finalize certificate exist”, and the numbers are in the Alpenglow post.&lt;/p&gt;




&lt;h2&gt;
  
  
  Confirmations: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How many confirmations does Solana need to be final?
&lt;/h3&gt;

&lt;p&gt;Thirty-two. “Finalized” means 32 blocks have been built on top of the one holding your transaction, which is about 8 seconds at 250 ms slots and 6.4 seconds at 200 ms.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does “confirmed” mean on Solana?
&lt;/h3&gt;

&lt;p&gt;More than two-thirds of the epoch’s stake has voted for the block at least once. It is a stake measurement, one vote deep, and it is the level most wallets show as a green tick.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does getSignatureStatuses show confirmations as null?
&lt;/h3&gt;

&lt;p&gt;Because the block has been rooted. Null is the finalized state, not an unknown; counts from 1 to 31 appear only while the block is still accumulating depth.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long should an exchange wait before crediting a Solana deposit?
&lt;/h3&gt;

&lt;p&gt;Display on confirmed and release on finalized. If a deposit has not confirmed within the blockhash lifetime of 150 slots, it did not land and will not.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three numbers
&lt;/h2&gt;

&lt;p&gt;Two-thirds of stake, voting once — that is “confirmed”, and it is what the green tick means.&lt;/p&gt;

&lt;p&gt;Thirty-two blocks deep — that is “finalized”, 8 seconds today and 6.4 next epoch.&lt;/p&gt;

&lt;p&gt;One hundred and twenty seconds — that is when the reference client stops waiting.&lt;/p&gt;

&lt;p&gt;Credit on the second, display on the first, and treat the third as the point at which something has gone wrong rather than slow.&lt;/p&gt;

&lt;p&gt;— The Number Moves With the Slot Time —&lt;/p&gt;

&lt;h3&gt;
  
  
  Confirmation times are slot counts times a slot length that keeps changing.
&lt;/h3&gt;

&lt;p&gt;The upgrades tracker reads the slot-time and Alpenglow gates from the chain every minute, so the seconds you quote match the regime actually in force.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.xroot.dev/upgrades?ref=blog" rel="noopener noreferrer"&gt;Open the Upgrades Tracker ↗&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The replacement for all of this is a certificate rather than a depth — &lt;a href="https://xroot.dev/blog/alpenglow-finality-in-numbers" rel="noopener noreferrer"&gt;Alpenglow finality in numbers&lt;/a&gt; — and the transaction that never confirms at all is &lt;a href="https://xroot.dev/blog/solana-transaction-dropped-no-error" rel="noopener noreferrer"&gt;a drop with no error&lt;/a&gt;. Every second-count above moves with &lt;a href="https://xroot.dev/blog/solana-200ms-slots-simd-0525" rel="noopener noreferrer"&gt;the slot-time ladder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;runtime/src/commitment.rs&lt;/code&gt; and &lt;code&gt;rpc-client/src/nonblocking/rpc_client.rs&lt;/code&gt;. Slot times and gate states were read from mainnet on 8 October 2026, epoch 1052.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>commitment</category>
      <category>deposits</category>
    </item>
    <item>
      <title>How Long to Unstake Solana: The 9% Cooldown Queue Explained</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:28 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/how-long-to-unstake-solana-the-9-cooldown-queue-explained-2c27</link>
      <guid>https://dev.to/sulimanmukhtar/how-long-to-unstake-solana-the-9-cooldown-queue-explained-2c27</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-unstaking-queue-cooldown" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You click “unstake”, the wallet says the stake is deactivating, and you wait for the epoch to roll over. It does. Your SOL is still not withdrawable, or only part of it is. Nothing is broken, and nobody told you about the queue.&lt;/p&gt;

&lt;p&gt;Solana limits how much stake can enter or leave the active set per epoch. The limit is a percentage of all stake on the network, not of yours, which means the time it takes for your SOL to become withdrawable depends on how many other people are leaving at the same time. Here is the rule, from the stake program’s constants and the runtime’s arithmetic, and how to read your own stake account to know where you are in the line.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stake does not switch off, it drains
&lt;/h2&gt;

&lt;p&gt;A delegated stake account has three portions at any moment: effective (earning and voting), activating (on its way in), and deactivating (on its way out). When you deactivate, the whole amount moves to the deactivating column at the next epoch boundary, and from there it &lt;strong&gt;drains&lt;/strong&gt; into “inactive” over one or more epochs. Only inactive lamports can be withdrawn.&lt;/p&gt;

&lt;p&gt;The drain is governed by one number: the warm-up/cool-down rate. It was &lt;strong&gt;25%&lt;/strong&gt; per epoch at launch and has been &lt;strong&gt;9%&lt;/strong&gt; since the &lt;code&gt;reduce_stake_warmup_cooldown&lt;/code&gt; feature activated. Both constants are still in the stake interface, in basis points — 2,500 and 900 — and the lower one is what the network uses today.&lt;/p&gt;




&lt;h2&gt;
  
  
  The formula, and why it is about everyone else
&lt;/h2&gt;

&lt;p&gt;For each epoch, the runtime computes how much of &lt;em&gt;your&lt;/em&gt; deactivating stake becomes inactive:&lt;/p&gt;

&lt;p&gt;your change = your deactivating portion × cluster effective stake × 900 ÷ (cluster deactivating portion × 10,000)&lt;/p&gt;

&lt;p&gt;Read the fraction. The network allows at most 9% of its total effective stake to leave per epoch. If the total deactivating that epoch is below that allowance, everyone drains fully in one epoch and you never notice a queue. If it is above — a large unstake wave, a validator exodus, an exchange moving its book — the allowance is shared out &lt;strong&gt;pro rata&lt;/strong&gt;, and your drain slows by exactly the ratio of the allowance to the demand.&lt;/p&gt;

&lt;p&gt;An example. Suppose 400 million SOL is effective and 60 million is deactivating in the same epoch. The allowance is 36 million (9% of 400). Your account drains 36 ÷ 60 = 60% this epoch, then 60% of the remainder the next, and so on. A 100 SOL unstake becomes 60 withdrawable after one boundary, 84 after two, 93.6 after three.&lt;/p&gt;

&lt;p&gt;Since 31 August 2026 that arithmetic runs in fixed-point integers (stake program v5.1.0) rather than floating point, so the result is exact and identical on every validator. It is also saturating: there is no path by which a crowded queue drains faster than the allowance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth knowing:&lt;/strong&gt; there is a floor. Each epoch, at least one lamport of a deactivating stake becomes inactive, so a drain always terminates and a dust-sized stake exits in a single epoch no matter how crowded the network is.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Warm-up is the same queue in reverse
&lt;/h2&gt;

&lt;p&gt;Activating stake is subject to the same 9% allowance. Delegate during a rush and your stake earns on only the portion that has become effective each epoch — the rest is waiting with everyone else’s. The symptom is a first reward that is smaller than you expected, which is a different post.&lt;/p&gt;

&lt;p&gt;The two queues are independent: a heavy inflow does not slow outflows, and vice versa.&lt;/p&gt;




&lt;h2&gt;
  
  
  Epochs are getting shorter, so the queue is getting faster in hours
&lt;/h2&gt;

&lt;p&gt;An epoch is 432,000 slots, and slots have been shrinking all year. At the 250 ms slot time in force when this was written, an epoch is about &lt;strong&gt;30 hours&lt;/strong&gt;; the final 200 ms step will bring it to &lt;strong&gt;24 hours&lt;/strong&gt;. A three-epoch drain that took six days at launch takes under four now, and three once that step lands.&lt;/p&gt;

&lt;p&gt;The percentage per epoch has not changed. Only the length of the epoch has.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reading your own position
&lt;/h2&gt;

&lt;p&gt;Your stake account carries the numbers you need: the delegation’s activation epoch, its deactivation epoch, and the stake amount. Combined with the network’s stake history sysvar — which records effective, activating and deactivating totals per epoch — the runtime’s own function returns your effective, activating and deactivating lamports for the current epoch. The reference CLI prints exactly this breakdown for any stake account, and any explorer that shows “activating” and “deactivating” rows is calling the same function.&lt;/p&gt;

&lt;p&gt;What you can withdraw right now is the inactive portion minus the rent-exempt reserve. If a wallet shows a withdrawable balance that does not match that, it is rounding.&lt;/p&gt;




&lt;h2&gt;
  
  
  Unstaking: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How long does it take to unstake Solana?
&lt;/h3&gt;

&lt;p&gt;At least one epoch boundary — about 30 hours at 250 ms slots, 24 hours at 200 ms — and longer if more than 9% of the network’s total stake is deactivating in the same epoch, because the allowance is shared pro rata.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is only part of my stake withdrawable after an epoch?
&lt;/h3&gt;

&lt;p&gt;Because the exit queue was over the 9% allowance that epoch. Your deactivating stake drained by the allowance-to-demand ratio, and the rest drains in the following epochs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I speed up unstaking?
&lt;/h3&gt;

&lt;p&gt;No. The rate is a network constant applied identically to every account. The only control you have is timing: deactivate when the queue is quiet, which the stake history sysvar shows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does the same queue apply when I stake?
&lt;/h3&gt;

&lt;p&gt;Yes. Activation is limited by the same 9% allowance, independently of deactivation, so stake delegated during a rush becomes effective over more than one epoch.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three things to know before you unstake
&lt;/h2&gt;

&lt;p&gt;It is not instant: the earliest your SOL can be fully withdrawable is the first epoch boundary after you deactivate, and only if the network’s exit queue is quiet.&lt;/p&gt;

&lt;p&gt;It is proportional: if more than 9% of all stake is leaving, your drain slows by the same ratio as everyone else’s, over as many epochs as it takes.&lt;/p&gt;

&lt;p&gt;It is predictable: the stake history sysvar is public, so the queue’s depth for the current epoch is readable before you deactivate, and the stake program’s math is now exact integer arithmetic that any tool can reproduce.&lt;/p&gt;

&lt;p&gt;— One Epoch Is the Unit —&lt;/p&gt;

&lt;h3&gt;
  
  
  Every drain is counted in epochs, and epochs keep getting shorter.
&lt;/h3&gt;

&lt;p&gt;The upgrades tracker shows which slot-time step is in force on each cluster, which is what turns “three epochs” into hours.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.xroot.dev/upgrades?ref=blog" rel="noopener noreferrer"&gt;Open the Upgrades Tracker ↗&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 1 SOL floor on new delegations is a separate rule — &lt;a href="https://xroot.dev/blog/solana-minimum-stake-delegation-1-sol" rel="noopener noreferrer"&gt;the minimum delegation&lt;/a&gt; — and the epoch length that sets this clock comes from &lt;a href="https://xroot.dev/blog/solana-200ms-slots-simd-0525" rel="noopener noreferrer"&gt;the slot-time ladder&lt;/a&gt;. What the stake earned on its way out arrives on its own schedule: &lt;a href="https://xroot.dev/blog/solana-staking-rewards-when-and-why-zero" rel="noopener noreferrer"&gt;when staking rewards are paid, and why one can be zero&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: the stake interface’s &lt;code&gt;warmup_cooldown_allowance.rs&lt;/code&gt;, &lt;code&gt;runtime/src/stake_history.rs&lt;/code&gt; and &lt;code&gt;feature-set/src/lib.rs&lt;/code&gt;. The live slot time was read from mainnet on 7 October 2026.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>staking</category>
      <category>unstaking</category>
    </item>
    <item>
      <title>When Solana Staking Rewards Arrive, and Why Yours Was Zero</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:26 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/when-solana-staking-rewards-arrive-and-why-yours-was-zero-19a5</link>
      <guid>https://dev.to/sulimanmukhtar/when-solana-staking-rewards-arrive-and-why-yours-was-zero-19a5</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-staking-rewards-when-and-why-zero" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The epoch ended an hour ago. Your friend’s stake account already shows its reward; yours does not. Or it shows one, and it is zero, with no explanation anywhere. Both are normal, and both are computable — the node knows exactly which block your reward lands in and exactly why it paid nothing, and it keeps neither fact anywhere you can see it.&lt;/p&gt;

&lt;p&gt;This post is both facts, from the runtime.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rewards are paid in a window, not at the boundary
&lt;/h2&gt;

&lt;p&gt;Staking rewards are not credited at the epoch boundary. They are credited over a &lt;strong&gt;window of blocks&lt;/strong&gt; at the start of the new epoch, one partition of stake accounts per block, because paying a million accounts in a single block would stall the network.&lt;/p&gt;

&lt;p&gt;The schedule is fixed by three rules:&lt;/p&gt;

&lt;p&gt;Distribution begins one block after the first block of the epoch.&lt;/p&gt;

&lt;p&gt;Each block pays a fixed number of stake accounts — &lt;strong&gt;4,096&lt;/strong&gt; at the original 400 ms slot, &lt;strong&gt;2,560&lt;/strong&gt; at the 250 ms slot in force when this was written, &lt;strong&gt;2,048&lt;/strong&gt; at 200 ms.&lt;/p&gt;

&lt;p&gt;The whole distribution must finish within the first &lt;strong&gt;10%&lt;/strong&gt; of the epoch. The number of partitions is the number of rewarded accounts divided by the per-block count, clamped to at most a tenth of the epoch’s slots.&lt;/p&gt;

&lt;p&gt;With a million rewarded stake accounts at 2,560 per block, that is about 390 blocks — under two minutes at 250 ms slots. A stake account paid in partition 300 sees its reward about a minute and a quarter after one paid in partition 1.&lt;/p&gt;




&lt;h2&gt;
  
  
  Which block is yours: a hash of your address
&lt;/h2&gt;

&lt;p&gt;The partition a stake account lands in is not random and not by size. It is a hash of the &lt;strong&gt;stake account’s address&lt;/strong&gt;, keyed by the &lt;strong&gt;blockhash of the epoch’s first block&lt;/strong&gt;, taken modulo the number of partitions. The runtime computes it to pay you; the RPC recomputes it to answer &lt;code&gt;getInflationReward&lt;/code&gt;, which is how it knows which block to look in.&lt;/p&gt;

&lt;p&gt;Everything in that formula is public the moment the epoch’s first block lands: the parent blockhash is in the block, the partition count follows from the number of rewarded accounts. Your reward block is therefore knowable at the start of the window, before it arrives. A wallet that shows “reward pending” could show “reward in block N, about 40 seconds away”. None does.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth knowing:&lt;/strong&gt; ask the RPC for a reward during the window and it refuses with error -32017, “epoch rewards period active”, and hands back the block height at which the distribution completes. That number is the end of the window for everyone, not your partition.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Nine reasons the node pays zero
&lt;/h2&gt;

&lt;p&gt;When the reward calculation skips a stake account, it records a reason. There are nine. The runtime discards them; here is what each one means for you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;DisabledInflation&lt;/strong&gt; — inflation is off for the cluster. Not a mainnet case.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;JustActivated&lt;/strong&gt; — the stake became effective this epoch and has no credits yet. Your first reward is next epoch, and it covers only the portion that was effective. See the &lt;a href="https://xroot.dev/blog/solana-unstaking-queue-cooldown" rel="noopener noreferrer"&gt;cool-down post&lt;/a&gt; for why that portion can be partial.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ZeroPoints&lt;/strong&gt; — the stake earned no points, which happens when it had no effective lamports during the epoch or its validator earned no credits.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ZeroPointValue&lt;/strong&gt; — the epoch’s total points were zero, so no reward could be priced. Rare; a cluster-level condition.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ZeroReward&lt;/strong&gt; — the computed reward rounded to zero lamports. Dust stakes on low-credit validators hit this.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ZeroCreditsAndReturnZero&lt;/strong&gt;, &lt;strong&gt;ZeroCreditsAndReturnCurrent&lt;/strong&gt;, &lt;strong&gt;ZeroCreditsAndReturnRewound&lt;/strong&gt; — the validator’s vote account earned no new credits this epoch. The middle one is the most common and the source code annotates it with a single word: delinquent. Your validator did not vote, and the stake delegated to it earned nothing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TooEarlyUnfairSplit&lt;/strong&gt; — the reward was so small that splitting it between you and the validator’s commission would have rounded one side to zero, so the runtime paid neither and did not advance your credits. Under tower voting your points carry over; under Alpenglow the residual lamport goes to the voter instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The practical reading: a zero reward on an account that had a reward last epoch almost always means one of the three “zero credits” cases — your validator was offline. A zero reward on a newly delegated account means JustActivated. A zero reward on a tiny account means ZeroReward or the unfair split.&lt;/p&gt;




&lt;h2&gt;
  
  
  The commission you were charged is two epochs old
&lt;/h2&gt;

&lt;p&gt;One more thing the runtime does that no dashboard shows. The commission applied to your reward is not the validator’s current rate. It is the rate from the vote state &lt;strong&gt;saved a full epoch before&lt;/strong&gt; the rewarded epoch — the source comment says this is “to prevent last minute commission rugs”. A validator that raises its commission today does not take the higher cut from this epoch’s reward or the next one’s.&lt;/p&gt;

&lt;p&gt;That protection predates the newer rule that delays all commission changes by an epoch, and the two now agree. It also means the number on your validator’s profile page today is not the number in your last reward, if it changed recently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Staking Rewards: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  When are Solana staking rewards paid?
&lt;/h3&gt;

&lt;p&gt;Over a window of blocks at the start of each epoch, starting one block after the epoch’s first block and finishing within the first 10% of the epoch. Each block pays a fixed partition of stake accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which block will my reward be in?
&lt;/h3&gt;

&lt;p&gt;The partition is a hash of your stake account’s address keyed by the epoch’s first blockhash, modulo the number of partitions. It is computable the moment the epoch’s first block lands.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did I get zero staking rewards this epoch?
&lt;/h3&gt;

&lt;p&gt;Most often because the validator earned no vote credits that epoch (it was delinquent), or because the stake only became effective this epoch. The runtime records one of nine reasons; the common ones are those two.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why was my reward smaller than the validator’s advertised commission implies?
&lt;/h3&gt;

&lt;p&gt;The commission applied is the rate saved a full epoch before the rewarded epoch, not the current one. A recent change does not apply to the reward you just received.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to check, in order
&lt;/h2&gt;

&lt;p&gt;Was the account effective last epoch? If it was activating, the first reward is partial and arrives next epoch.&lt;/p&gt;

&lt;p&gt;Did the validator vote? Zero credits in its vote account for the epoch means a zero reward for everyone delegated to it, with no notice.&lt;/p&gt;

&lt;p&gt;Is the window still open? If the RPC returns -32017, the distribution is in progress; your partition may simply be later than your friend’s.&lt;/p&gt;

&lt;p&gt;Is the stake tiny? Rewards below one lamport, or too small to split with the commission, are not paid.&lt;/p&gt;

&lt;p&gt;Every one of these is a plain account read. The node computed the answer when it skipped you; it just did not write it down.&lt;/p&gt;

&lt;p&gt;The commission taken from that reward has its own delays — &lt;a href="https://xroot.dev/blog/solana-validator-block-revenue-sharing-two-commissions" rel="noopener noreferrer"&gt;two commissions, one epoch delay&lt;/a&gt; — and under Alpenglow the reward itself changes shape: &lt;a href="https://xroot.dev/blog/alpenglow-vote-rewards-leader-split" rel="noopener noreferrer"&gt;half of every vote reward goes to the leader&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;runtime/src/bank/partitioned_epoch_rewards/mod.rs&lt;/code&gt;, &lt;code&gt;runtime/src/inflation_rewards/points.rs&lt;/code&gt; and &lt;code&gt;rpc/src/rpc.rs&lt;/code&gt;. Per-block counts follow the slot regime in force when this was written.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>staking</category>
      <category>rewards</category>
    </item>
    <item>
      <title>Solana RPC Error Codes Explained: -32001 to -32021</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:24 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/solana-rpc-error-codes-explained-32001-to-32021-b7g</link>
      <guid>https://dev.to/sulimanmukhtar/solana-rpc-error-codes-explained-32001-to-32021-b7g</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-rpc-error-codes-explained" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;JSON-RPC reserves the codes from -32000 to -32099 for server-defined errors, and Solana’s node defines twenty-one of them, -32001 through -32021. Most client libraries pass them through as a number and a string, parse two of them structurally, and leave you to search the number. Here is the whole list from the node’s source: what each code means, the message and data the node attaches, and the client action it calls for.&lt;/p&gt;

&lt;p&gt;The useful discovery is that several of these errors are not failures. They are the node telling you something precise — its own lag, its retention floor, the block height a reward period ends — that no successful response would have told you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Transactions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;-32002 — SendTransactionPreflightFailure.&lt;/strong&gt; The simulation before send failed. The &lt;code&gt;data&lt;/code&gt; field carries the &lt;strong&gt;entire simulation result&lt;/strong&gt;: the error, the logs, units consumed, return data. This is the one code every client should parse, because the logs inside it are the diagnosis. Action: read the data; do not resend unchanged.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32003 — TransactionSignatureVerificationFailure.&lt;/strong&gt; A signature does not verify against the message. Action: a client bug; check the signing order and that the message was not modified after signing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32006 — TransactionPrecompileVerificationFailure.&lt;/strong&gt; An ed25519, secp256k1 or secp256r1 precompile instruction failed verification; the message names the precompile error. Action: for secp256r1 the usual cause is a high-S signature; normalise and retry.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32013 — TransactionSignatureLenMismatch.&lt;/strong&gt; The number of signatures does not match the number the message requires. Action: client bug.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32015 — UnsupportedTransactionVersion.&lt;/strong&gt; You asked for a versioned transaction without declaring support. The message contains the fix verbatim: retry with &lt;code&gt;maxSupportedTransactionVersion&lt;/code&gt; set to the version it names. Action: do exactly that.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Node state
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;-32005 — NodeUnhealthy.&lt;/strong&gt; The node is behind the cluster. If it knows by how much, the message reads “Node is behind by N slots” and &lt;code&gt;data&lt;/code&gt; carries &lt;code&gt;numSlotsBehind&lt;/code&gt;; otherwise “Node is unhealthy”. This is the only place a node volunteers its own lag. Action: fail over, and log the number — it is a free health metric for your provider.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32008 — NoSnapshot.&lt;/strong&gt; The node has no snapshot to serve. Action: another node.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32016 — MinContextSlotNotReached.&lt;/strong&gt; You asked for a response at or after a slot (&lt;code&gt;minContextSlot&lt;/code&gt;) that this node has not reached; &lt;code&gt;data&lt;/code&gt; carries the node’s actual &lt;code&gt;contextSlot&lt;/code&gt;. Action: retry after a short wait, or route to a node that is ahead. The attached slot tells you how far behind this one is, which makes the code a free staleness probe.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32021 — NoSlotHistory.&lt;/strong&gt; The SlotHistory sysvar is unavailable, so a request that depends on it (block production, skipped-slot checks) cannot be answered. Action: another node.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  History and archives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;-32001 — BlockCleanedUp.&lt;/strong&gt; The slot you asked for is older than the node’s ledger retains. The message states “First available block: N” — the node’s retention floor. Action: route older queries to an archive endpoint, and record N; it is the boundary between hot and cold history on that provider.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32004 — BlockNotAvailable.&lt;/strong&gt; The slot is within retention but the block is not present on this node — typically a slot it has not received or confirmed yet. Action: retry, or try another node.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32007 — SlotSkipped.&lt;/strong&gt; The slot produced no block, or is missing because the node jumped to a recent snapshot. Action: not an error for your query; move to the next slot.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32009 — LongTermStorageSlotSkipped.&lt;/strong&gt; The archive (Bigtable) has no block for the slot. Action: as above.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32011 — TransactionHistoryNotAvailable.&lt;/strong&gt; The node does not serve transaction history at all (history is disabled on it). Action: a different provider.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32014 — BlockStatusNotAvailableYet.&lt;/strong&gt; The block exists but its status (confirmed/finalized) is not yet known on this node. Action: retry.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32019 — LongTermStorageUnreachable.&lt;/strong&gt; The archive backend could not be reached. Action: retry later; the hot path still works.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32020 — FilterTransactionNotFound.&lt;/strong&gt; A &lt;code&gt;before&lt;/code&gt; or &lt;code&gt;until&lt;/code&gt; signature passed to a history query could not be found. Action: the pivot is wrong or not yet archived; drop it or wait.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Indexes, scans and epochs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;-32012 — ScanError.&lt;/strong&gt; An accounts scan behind &lt;code&gt;getProgramAccounts&lt;/code&gt; or a similar query failed or was aborted on the node; the message carries the scan error. Action: narrow the filters, or retry on a node with the index you need.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32010 — KeyExcludedFromSecondaryIndex.&lt;/strong&gt; You asked &lt;code&gt;getProgramAccounts&lt;/code&gt; with a filter the node could have served from its token index, but the key you filtered on is excluded from that index on this node. Action: the query will not be fast here; narrow it or use a provider with a full index.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32017 — EpochRewardsPeriodActive.&lt;/strong&gt; You asked for an inflation reward while the epoch’s rewards are still being distributed; &lt;code&gt;data&lt;/code&gt; carries &lt;code&gt;rewards_complete_block_height&lt;/code&gt;. Action: wait until the chain passes that block height, then retry. The number is the end of the distribution window for everyone.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;-32018 — SlotNotEpochBoundary.&lt;/strong&gt; A query that must be made at an epoch boundary was made at another slot. Action: use the epoch’s first slot.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What the reference client does with them
&lt;/h2&gt;

&lt;p&gt;The stock Rust client parses exactly two of these into typed errors: -32002 and -32005. Everything else arrives as a code and a message string. The structured data the node attaches to -32016 (the actual context slot), -32017 (the completion height) and -32001 (the first available block) is sent and then discarded by the client, unless you read the raw response yourself.&lt;/p&gt;

&lt;p&gt;If you build on top of an RPC — a bot, an indexer, a wallet backend — those three payloads are worth catching. They turn three failures into three measurements.&lt;/p&gt;




&lt;h2&gt;
  
  
  RPC Errors: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What does Solana RPC error -32005 mean?
&lt;/h3&gt;

&lt;p&gt;The node is unhealthy or behind the cluster. If it knows its lag, the message reads “Node is behind by N slots” and the data carries the number. Fail over to another node and keep the number as a health signal.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does error -32002 mean when sending a transaction?
&lt;/h3&gt;

&lt;p&gt;The preflight simulation failed. The error’s data field contains the full simulation result, including the program logs, which is where the actual cause is.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I fix -32015 UnsupportedTransactionVersion?
&lt;/h3&gt;

&lt;p&gt;Retry the request with maxSupportedTransactionVersion set to the version named in the message. The message states the fix verbatim.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does -32016 MinContextSlotNotReached mean?
&lt;/h3&gt;

&lt;p&gt;You asked for data at or after a slot this node has not reached. The data carries the node’s actual context slot, so you know how far behind it is; retry shortly or route to a node that is ahead.&lt;/p&gt;




&lt;h2&gt;
  
  
  The ones worth handling specially
&lt;/h2&gt;

&lt;p&gt;-32002: read the simulation in &lt;code&gt;data&lt;/code&gt;; it is the diagnosis.&lt;/p&gt;

&lt;p&gt;-32005 and -32016: read the slot numbers; they are the node’s lag, measured by the node.&lt;/p&gt;

&lt;p&gt;-32001: read the first available block; it is the provider’s retention boundary.&lt;/p&gt;

&lt;p&gt;-32015: do what the message says.&lt;/p&gt;

&lt;p&gt;-32017: wait for the block height it gives you.&lt;/p&gt;

&lt;p&gt;The rest are “try another node” or “you have a client bug”, and the message says which.&lt;/p&gt;

&lt;p&gt;The worst failures produce no code at all — &lt;a href="https://xroot.dev/blog/solana-transaction-dropped-no-error" rel="noopener noreferrer"&gt;the seven places a transaction disappears&lt;/a&gt;. -32015 is the code &lt;a href="https://xroot.dev/blog/solana-transaction-v1" rel="noopener noreferrer"&gt;transaction v1&lt;/a&gt; made common, and -32017’s block height is explained in &lt;a href="https://xroot.dev/blog/solana-staking-rewards-when-and-why-zero" rel="noopener noreferrer"&gt;when staking rewards arrive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;rpc-client-api/src/custom_error.rs&lt;/code&gt; and &lt;code&gt;rpc-client/src/http_sender.rs&lt;/code&gt;. Codes are added with releases — check the list against the version you run.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>rpc</category>
      <category>debugging</category>
    </item>
    <item>
      <title>“Log Truncated” on Solana: The 10,000-Byte Rule Explained</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:22 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/log-truncated-on-solana-the-10000-byte-rule-explained-2im2</link>
      <guid>https://dev.to/sulimanmukhtar/log-truncated-on-solana-the-10000-byte-rule-explained-2im2</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-log-truncated-10000-bytes" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The transaction failed. You open it in the explorer, scroll to the program logs to find the error, and the logs stop mid-flow with two words: &lt;code&gt;Log truncated&lt;/code&gt;. The error, if the program printed one, is somewhere in the part you cannot see.&lt;/p&gt;

&lt;p&gt;The limit is small, it is applied in a way that drops more than you expect, and it applies to simulation too, which is why “I’ll just simulate it and read the logs” does not work either. Here are the rules, from the log collector, and what logging costs you in compute so you can stop paying for the lines that get cut.&lt;/p&gt;




&lt;h2&gt;
  
  
  The limit, and the way it is applied
&lt;/h2&gt;

&lt;p&gt;Every transaction’s program logs go into one collector with a byte budget of &lt;strong&gt;10,000&lt;/strong&gt; — ten thousand, decimal, not ten kibibytes. Each line a program emits is counted against it.&lt;/p&gt;

&lt;p&gt;The check runs before a line is stored: if the bytes already written are at or above the limit, the line is dropped. The comparison is &lt;code&gt;&amp;gt;=&lt;/code&gt;, not &lt;code&gt;&amp;gt;&lt;/code&gt;, with a consequence that is often missed: the line that would cross the limit is not cut short to fit — it is &lt;strong&gt;dropped whole&lt;/strong&gt;, and so is every line after it. Then the collector appends its own line, “Log truncated”, once, and stops.&lt;/p&gt;

&lt;p&gt;The collector’s own test spells out the arithmetic: 20,000 attempts to write a one-byte line produce exactly 9,999 stored lines, then the marker. A program that logs a 2,000-byte line at byte 9,000 loses the whole line.&lt;/p&gt;




&lt;h2&gt;
  
  
  Simulation is capped too
&lt;/h2&gt;

&lt;p&gt;The natural workaround — simulate the transaction and read the full logs — does not work, because the simulation path uses the same collector with the same default. The runtime’s simulation entry point passes “no limit” to the collector constructor, but “no limit” at that layer means “use the default”, and the default is 10,000.&lt;/p&gt;

&lt;p&gt;There is exactly one way to construct an unlimited collector, and nothing in the validator calls it. Full logs are not available through any RPC on any public node.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth knowing:&lt;/strong&gt; the limit is a per-validator flag. An operator can raise &lt;code&gt;--log-messages-bytes-limit&lt;/code&gt; on their node, which means the same transaction can return different logs from different RPC endpoints. If your provider’s node has raised it, you will see more; if yours is truncated and a friend’s is not, that is why.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Where the full logs actually go
&lt;/h2&gt;

&lt;p&gt;Every line the collector receives is also emitted through the validator’s ordinary logging at debug level, under a target named &lt;code&gt;stable_log&lt;/code&gt;, before the byte budget is applied. An operator running a node at debug verbosity for that target sees the untruncated stream in the node’s log file — the one place the limit does not reach.&lt;/p&gt;

&lt;p&gt;That is not a feature you can use from a wallet or an explorer. It is a reason to run your own node for debugging, or to ask your provider whether they can.&lt;/p&gt;

&lt;p&gt;One more way a line goes missing, unrelated to the budget: the logging macro the runtime uses tries to borrow the collector, and if the collector is already borrowed at that moment, the line is silently dropped with no marker at all. It is rare and it is non-deterministic, which is the worst kind of missing log.&lt;/p&gt;




&lt;h2&gt;
  
  
  What each log line costs you
&lt;/h2&gt;

&lt;p&gt;Logging is not free, and the cost is charged whether or not the line survives the budget.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;msg!&lt;/code&gt; with a string — the &lt;code&gt;sol_log_&lt;/code&gt; syscall — costs the larger of 100 compute units and the string’s length in bytes. A 40-character message costs 100; a 4,000-byte dump of an account costs 4,000.&lt;/p&gt;

&lt;p&gt;Logging a number (&lt;code&gt;sol_log_64&lt;/code&gt;) costs 100. Logging a public key (&lt;code&gt;sol_log_pubkey&lt;/code&gt;) costs 100.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sol_log_data&lt;/code&gt;, the structured variant, costs 100 × (1 + number of fields) plus the total bytes — so three 32-byte fields cost 100 × 4 + 96 = 496.&lt;/p&gt;

&lt;p&gt;A program that logs generously can spend a meaningful fraction of its compute budget on lines nobody will see past byte 10,000. And because the leader ranks transactions by fee divided by requested compute, a bloated compute limit to cover logging also lowers your landing rank.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to do instead
&lt;/h2&gt;

&lt;p&gt;Log less, and log the thing that matters first. The error you need to read should be the first line, not the last.&lt;/p&gt;

&lt;p&gt;Log bytes, not formatted strings. A formatted string of a struct is long; its discriminant and one or two fields are not.&lt;/p&gt;

&lt;p&gt;Use return data for structured output. A program can set up to 1,024 bytes of return data that the RPC surfaces in simulation and transaction metadata, outside the log budget, and it is the right channel for “here is the result” rather than “here is a diary”.&lt;/p&gt;

&lt;p&gt;Put the diagnostics behind a flag. A compile-time feature that enables verbose logging on devnet and strips it on mainnet costs nothing in production and keeps the budget for the line you need.&lt;/p&gt;




&lt;h2&gt;
  
  
  Log Truncation: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What does “Log truncated” mean on Solana?
&lt;/h3&gt;

&lt;p&gt;The transaction’s program logs exceeded the 10,000-byte collector limit. The line that crossed the limit and every line after it were dropped, and the collector appended “Log truncated” once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are my logs truncated in simulateTransaction too?
&lt;/h3&gt;

&lt;p&gt;Simulation uses the same collector with the same default. “No limit” at the simulation entry point resolves to the 10,000-byte default, and no RPC path constructs an unlimited collector.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much compute does msg! cost?
&lt;/h3&gt;

&lt;p&gt;The larger of 100 compute units and the message length in bytes. Numbers and public keys cost 100 each; sol_log_data costs 100 per field plus one, plus the bytes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I get the full logs anywhere?
&lt;/h3&gt;

&lt;p&gt;On a node whose operator raised the per-validator log limit, or from the node’s own debug log, which receives every line before the budget applies. Neither is available from a standard public RPC.&lt;/p&gt;




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

&lt;p&gt;Ten thousand bytes per transaction, applied as “drop the crossing line and everything after it”, in simulation as well as execution.&lt;/p&gt;

&lt;p&gt;One hundred compute units minimum per line, rising with length, charged whether the line is kept or not.&lt;/p&gt;

&lt;p&gt;The second number is the one you control.&lt;/p&gt;

&lt;p&gt;A truncated log often hides the line that explains the failure, which is when &lt;a href="https://xroot.dev/blog/solana-rpc-error-codes-explained" rel="noopener noreferrer"&gt;the RPC error codes&lt;/a&gt; carry the rest of the diagnosis — and a simulation can be &lt;a href="https://xroot.dev/blog/solana-honeypot-simulation-aware-programs" rel="noopener noreferrer"&gt;deliberately misleading&lt;/a&gt; even with complete logs. What each log call costs feeds straight into &lt;a href="https://xroot.dev/blog/solana-transaction-priority-formula-compute-limit" rel="noopener noreferrer"&gt;the leader’s ranking formula&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;svm-log-collector/src/lib.rs&lt;/code&gt;, &lt;code&gt;syscalls/src/logging.rs&lt;/code&gt; and &lt;code&gt;validator/src/commands/run/args.rs&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>programs</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Stake-Weighted QoS on Solana, With the Actual Formula</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:20 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/stake-weighted-qos-on-solana-with-the-actual-formula-32hm</link>
      <guid>https://dev.to/sulimanmukhtar/stake-weighted-qos-on-solana-with-the-actual-formula-32hm</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-stake-weighted-qos-formula" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Every Solana RPC provider now sells some version of “staked connections”: your transactions ride a validator’s stake to the leader’s door, so they get in when unstaked traffic does not. The pitch is right. The mechanism is a formula in the validator’s QUIC server, and reading it tells you three things the pitch does not — how much a connection actually gets, where extra stake stops helping, and why a sender on the other side of the planet is given more room than one next door.&lt;/p&gt;




&lt;h2&gt;
  
  
  The door: connections and streams
&lt;/h2&gt;

&lt;p&gt;A leader accepts transactions over QUIC. Each sender holds a &lt;strong&gt;connection&lt;/strong&gt;, and sends each transaction on a &lt;strong&gt;stream&lt;/strong&gt; inside it. The leader limits both.&lt;/p&gt;

&lt;p&gt;Connections are split into two pools, each &lt;strong&gt;2,000&lt;/strong&gt; deep by default: one for senders whose identity holds stake, one for everyone else. A staked identity may hold up to 16 connections, an unstaked one up to 8, and each IP address may open 8 new connections per minute by default — the validator binary raises that to 32 to tolerate container hosts.&lt;/p&gt;

&lt;p&gt;Staked senders are keyed by &lt;strong&gt;public key&lt;/strong&gt;, not IP: the 16-connection cap and any ban follow the identity across every address it connects from. All connections under one identity share a single stream counter, so opening more connections buys no more streams.&lt;/p&gt;




&lt;h2&gt;
  
  
  The stream allowance, exactly
&lt;/h2&gt;

&lt;p&gt;How many streams a connection may have in flight at once is the number that decides whether your transactions are admitted under load. For a staked sender:&lt;/p&gt;

&lt;p&gt;streams = clamp( stake_ratio × (100,000 − 128) + 128, 128, 512 )&lt;/p&gt;

&lt;p&gt;where stake_ratio is the sender’s stake divided by total stake. Then every sender, staked or not, has the result scaled by round-trip time:&lt;/p&gt;

&lt;p&gt;streams × clamp(rtt_ms, 50, 350) ÷ 50&lt;/p&gt;

&lt;p&gt;An unstaked sender gets a flat &lt;strong&gt;128&lt;/strong&gt; before the RTT scaling.&lt;/p&gt;

&lt;p&gt;Three things fall out of the arithmetic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The ceiling is low.&lt;/strong&gt; The formula reaches 512 when stake_ratio × 99,872 + 128 = 512, which is a stake ratio of about &lt;strong&gt;0.38%&lt;/strong&gt;. A sender holding more than roughly 0.38% of all stake — on the order of 1.5 million SOL at today’s totals — gets exactly the same 512 streams as one holding 0.38%. Beyond that point, stake buys zero concurrency.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Distance is rewarded.&lt;/strong&gt; The RTT factor runs from 1× at 50 ms to &lt;strong&gt;7×&lt;/strong&gt; at 350 ms. A peer 350 ms away gets seven times the in-flight streams of one 50 ms away. That is bandwidth-delay-product scaling — the far peer needs more in flight to keep the same throughput — but it means a sender who measures a long RTT to a leader is granted more room, not less.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;There is a trapdoor at the bottom.&lt;/strong&gt; A staked identity whose stake ratio is below 1/50,000 — about 8,000 SOL at a 400-million-SOL total — is reclassified as unstaked. Small stake is not a small lane; it is no lane.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Throttling: when the budget is actually enforced
&lt;/h2&gt;

&lt;p&gt;The allowance above is a cap on concurrency. A second mechanism caps &lt;strong&gt;rate&lt;/strong&gt;: the leader admits at most 500 new streams per millisecond across all senders, and it meters per 100 ms window.&lt;/p&gt;

&lt;p&gt;The unstaked pool is throttled always: each unstaked connection gets 20 streams per 100 ms, derived from a 200-transactions-per-second budget per connection.&lt;/p&gt;

&lt;p&gt;The staked pool is throttled &lt;strong&gt;only under load&lt;/strong&gt;. The server tracks an exponential moving average of stream load, and until that average reaches 95% of capacity, a staked sender may use the whole staked budget — 40,000 streams per 100 ms. Past 95%, each staked sender’s share becomes its stake ratio times 40,000, with a floor of 21.&lt;/p&gt;

&lt;p&gt;So the system is bimodal. In a quiet block, a staked connection with any stake at all is effectively unlimited. In a hot block, it gets its proportional share, and the share of a small validator is small.&lt;/p&gt;




&lt;h2&gt;
  
  
  How stake is bought: the override
&lt;/h2&gt;

&lt;p&gt;The stake the server consults is not only the validator’s real delegation. A validator can grant &lt;strong&gt;virtual stake&lt;/strong&gt; to any peer identity through its admin interface, and the server refreshes its view of staked nodes every &lt;strong&gt;5 seconds&lt;/strong&gt;. That is the mechanism under every “staked connections” product: the provider’s sending identity is given stake it does not hold, by validators it has an arrangement with, and the leader treats it accordingly.&lt;/p&gt;

&lt;p&gt;Two properties of the override matter to a buyer. It takes effect, or is revoked, within five seconds. And it only counts at validators that have granted it — a lane sold by one validator is a lane at that validator’s slots, which are a fraction of the schedule.&lt;/p&gt;

&lt;p&gt;Stake is also revalidated on a randomised one-to-two-hour cycle, and a stale cache can over-grant by at most a factor of two. Increases never evict an existing connection; a newcomer with more stake evicts a lower-staked connection only by winning a two-sample lottery, and if it loses it is silently demoted to the unstaked pool.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this means for a transaction you send through an RPC
&lt;/h2&gt;

&lt;p&gt;Your wallet never holds a connection to a leader; your RPC provider’s sending node does. The node’s identity, its granted stake, and its RTT to the current leader decide its stream allowance, and under load that allowance is what your transaction competes for.&lt;/p&gt;

&lt;p&gt;If the provider’s node is unstaked, your transaction is in the 128-stream pool with every other unstaked sender’s, throttled to 20 streams per 100 ms per connection, always. If it holds a sliver of stake above the 1/50,000 floor, it is in the staked pool, unthrottled until the leader is 95% loaded, and then proportional. If it holds 0.38% or more, it has the maximum, and more stake than that is marketing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stake-Weighted QoS: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is stake-weighted QoS on Solana?
&lt;/h3&gt;

&lt;p&gt;A rule in the leader’s QUIC server that allocates connection slots and in-flight streams by the sender’s share of stake. Staked senders get between 128 and 512 concurrent streams, scaled by round-trip time; unstaked senders get 128 and are rate-limited always.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much stake does an RPC need for the maximum lane?
&lt;/h3&gt;

&lt;p&gt;About 0.38% of total stake. At that ratio the formula reaches its 512-stream cap, and additional stake buys no more concurrency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a validator sell its stake-weighted lane?
&lt;/h3&gt;

&lt;p&gt;Yes. A validator can grant virtual stake to a peer identity through its admin interface; the server refreshes the grant within five seconds. The lane applies only at that validator’s own slots.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does a far-away sender get more streams?
&lt;/h3&gt;

&lt;p&gt;The allowance is multiplied by round-trip time, clamped between 50 and 350 ms and divided by 50, so a 350 ms peer gets seven times the in-flight streams of a 50 ms peer. It is bandwidth-delay scaling, not a reward.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three numbers to ask a provider for
&lt;/h2&gt;

&lt;p&gt;Their sending identity’s stake ratio — real or granted — against the 1/50,000 floor and the 0.38% ceiling.&lt;/p&gt;

&lt;p&gt;Which validators have granted it, because the lane only exists at those validators’ slots.&lt;/p&gt;

&lt;p&gt;Their RTT to leaders, because the server multiplies the allowance by it.&lt;/p&gt;

&lt;p&gt;Nothing else in the pitch changes the formula.&lt;/p&gt;

&lt;p&gt;This is door three of &lt;a href="https://xroot.dev/blog/solana-transaction-dropped-no-error" rel="noopener noreferrer"&gt;the seven places a transaction disappears&lt;/a&gt;, and it decides who is heard before &lt;a href="https://xroot.dev/blog/solana-transaction-priority-formula-compute-limit" rel="noopener noreferrer"&gt;the fee ranking&lt;/a&gt; is ever consulted. Stake buys a seat in consensus too — &lt;a href="https://xroot.dev/blog/alpenglow-validator-admission-2000-seats" rel="noopener noreferrer"&gt;the 2,000-seat cap&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;streamer/src/nonblocking/swqos.rs&lt;/code&gt;, &lt;code&gt;streamer/src/quic.rs&lt;/code&gt; and &lt;code&gt;core/src/staked_nodes_updater_service.rs&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>quic</category>
      <category>networking</category>
    </item>
    <item>
      <title>Passkeys on Solana: Why Half of WebAuthn Signatures Fail</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:18 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/passkeys-on-solana-why-half-of-webauthn-signatures-fail-1c94</link>
      <guid>https://dev.to/sulimanmukhtar/passkeys-on-solana-why-half-of-webauthn-signatures-fail-1c94</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-passkeys-secp256r1-webauthn" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A passkey wallet is the obvious future: no seed phrase, a thumbprint or a face, the device’s secure chip holding the key. Solana made it possible by adding native verification for the curve those chips use — P-256, called secp256r1 in the code — as a precompile, the same way it verifies Ethereum-style secp256k1 signatures.&lt;/p&gt;

&lt;p&gt;Then developers wired it up and found that roughly every second signature failed. Nothing was wrong with the authenticator and nothing was wrong with the chain. The two disagree about what a valid signature looks like, and the chain’s rule is the stricter one. Here are the rules the precompile enforces, what each verification costs you in fee and block space, and the one-line fix for the failures.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the precompile checks, in order
&lt;/h2&gt;

&lt;p&gt;A secp256r1 instruction carries a count byte, a reserved byte, an offsets table, and then the signatures, public keys and messages it references. The verifier reads it in this order:&lt;/p&gt;

&lt;p&gt;The count is &lt;code&gt;data[0]&lt;/code&gt;. Zero is rejected. &lt;strong&gt;More than eight&lt;/strong&gt; is rejected. That is the hard cap per instruction; a transaction needing more signatures needs more instructions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;data[1]&lt;/code&gt; is read by nobody. The source says so in a comment: “we do not check or use the byte at data[1]”. It is one free byte per instruction that the consensus ignores.&lt;/p&gt;

&lt;p&gt;Each signature is checked for &lt;strong&gt;low S&lt;/strong&gt;. The S component must be at most half the curve order; anything above is rejected as an invalid signature, even though it is mathematically valid.&lt;/p&gt;

&lt;p&gt;Each public key is validated as a point on the curve, and the signature is verified against the message through OpenSSL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why half of them fail: high S
&lt;/h2&gt;

&lt;p&gt;An ECDSA signature has two halves, R and S, and for any valid S there is a second valid value, the curve order minus S. Both verify. One is “low” (at most half the order) and one is “high”. A signer that does not normalise will produce each about half the time.&lt;/p&gt;

&lt;p&gt;Bitcoin and Ethereum reject high-S signatures to prevent malleability — the ability to produce a second, different-looking signature for the same message — and Solana’s precompile does the same. WebAuthn authenticators do not normalise. They return whichever half the hardware produced, and about half the time that is the high one.&lt;/p&gt;

&lt;p&gt;The fix is one line, and it belongs in the client before the transaction is built: if S is greater than half the order, replace it with the order minus S. The signature stays valid, the authenticator is none the wiser, and the precompile accepts it every time. A passkey wallet that does not do this will fail roughly half its transactions and blame the network.&lt;/p&gt;




&lt;h2&gt;
  
  
  What each signature costs
&lt;/h2&gt;

&lt;p&gt;Two costs, charged in different places.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Fee.&lt;/strong&gt; Every precompile signature counts as a signature for the base fee. The fee calculation sums transaction signatures, ed25519 signatures, secp256k1 signatures and secp256r1 signatures, and multiplies the total by the per-signature rate. A transaction with one fee-payer signature and one passkey signature pays two signatures’ worth of base fee — 10,000 lamports at the default rate, not 5,000.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Block space.&lt;/strong&gt; The cost model charges &lt;strong&gt;4,800 compute units&lt;/strong&gt; per secp256r1 verification — 160 microseconds at the 30-units-per-microsecond ratio the model uses. For comparison an ed25519 precompile signature costs 2,400 and a secp256k1 one 6,690. Those units are added to your transaction’s cost, which is the denominator in the leader’s ranking formula, so a passkey transaction ranks lower than an identical ed25519 one at the same priority fee.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The eight-per-instruction cap interacts with the cost: the verifier sets up its curve context once per instruction, so eight signatures in one instruction cost less validator time than eight instructions of one signature, even though the cost model charges the same.&lt;/p&gt;




&lt;h2&gt;
  
  
  How a passkey transaction is actually built
&lt;/h2&gt;

&lt;p&gt;The precompile verifies a signature; it does not authorise anything by itself. The pattern that makes a passkey a wallet is:&lt;/p&gt;

&lt;p&gt;A smart-wallet program owns the user’s assets and stores the user’s P-256 public key.&lt;/p&gt;

&lt;p&gt;A transaction carries a secp256r1 precompile instruction with the passkey signature over a message, followed by an instruction to the smart-wallet program.&lt;/p&gt;

&lt;p&gt;The smart-wallet program reads the precompile instruction from the transaction’s instruction sysvar, confirms it verified the expected public key over the expected message, and only then moves assets.&lt;/p&gt;

&lt;p&gt;A relayer or the user pays the fee with an ordinary ed25519 key, because the fee payer must still be a Solana keypair. That is why the base fee counts two signatures.&lt;/p&gt;

&lt;p&gt;Two consequences follow. The passkey never signs a Solana transaction directly — it signs a message the program checks — so replay protection is the program’s job, not the runtime’s. And a transaction that references the wrong instruction index, or a message the program does not expect, fails in the program, not in the precompile.&lt;/p&gt;




&lt;h2&gt;
  
  
  The limits you will hit first
&lt;/h2&gt;

&lt;p&gt;Eight signatures per instruction, and the instruction count and size limits of the transaction itself. A P-256 signature is 64 bytes, a compressed public key 33, and the message whatever the program expects — WebAuthn messages include the authenticator data and client data hash, which are not small. In a 1,232-byte legacy transaction, two or three passkey signatures fill it. Transaction v1’s 4,096-byte envelope is the comfortable home for multi-signature passkey flows.&lt;/p&gt;

&lt;p&gt;The precompile is feature-gated, and on mainnet the gate has been active since epoch 800. Check its state on any other cluster you target before you ship a wallet that depends on it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Passkeys: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does Solana support passkeys natively?
&lt;/h3&gt;

&lt;p&gt;Solana verifies P-256 (secp256r1) signatures through a precompile, which is the curve passkeys and WebAuthn authenticators use. A smart-wallet program reads the verified signature and decides what it authorises; the precompile is feature-gated, so check its state on your target cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do my WebAuthn signatures fail on Solana?
&lt;/h3&gt;

&lt;p&gt;The precompile rejects high-S signatures. Authenticators produce high S about half the time. Normalise S to the low half (order minus S when S exceeds half the order) before submitting.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does a passkey signature cost on Solana?
&lt;/h3&gt;

&lt;p&gt;A full signature’s share of the base fee, plus 4,800 compute units of block-space cost per verification. A transaction with a fee payer and one passkey pays two signatures of base fee.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many passkey signatures fit in one instruction?
&lt;/h3&gt;

&lt;p&gt;Eight. The precompile rejects a count of zero or more than eight; additional signatures need additional instructions, and the transaction size limit applies.&lt;/p&gt;




&lt;h2&gt;
  
  
  The checklist for a passkey integration
&lt;/h2&gt;

&lt;p&gt;Normalise S to the low half before building the transaction. This alone removes the “random” failures.&lt;/p&gt;

&lt;p&gt;Budget two signatures of base fee per passkey transaction, and 4,800 compute units of block space per verification.&lt;/p&gt;

&lt;p&gt;Keep to eight signatures per precompile instruction and read the transaction size as you add them.&lt;/p&gt;

&lt;p&gt;Verify, in your program, that the precompile instruction you are trusting checked the key and message you expect. The precompile proves a signature exists; your program decides what it means.&lt;/p&gt;

&lt;p&gt;Each passkey signature is block space like any other — &lt;a href="https://xroot.dev/blog/solana-transaction-priority-formula-compute-limit" rel="noopener noreferrer"&gt;the ranking formula&lt;/a&gt; counts its 4,800 units — and signed approvals that must wait for a human pair naturally with &lt;a href="https://xroot.dev/blog/solana-durable-nonce-pre-signed-transactions" rel="noopener noreferrer"&gt;a durable nonce&lt;/a&gt;. Verification data fits more comfortably in &lt;a href="https://xroot.dev/blog/solana-transaction-v1" rel="noopener noreferrer"&gt;a 4,096-byte v1 transaction&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;precompiles/src/secp256r1.rs&lt;/code&gt;, &lt;code&gt;cost-model/src/block_cost_limits.rs&lt;/code&gt; and &lt;code&gt;fee/src/lib.rs&lt;/code&gt;. The &lt;code&gt;enable_secp256r1_precompile&lt;/code&gt; gate has been active on mainnet since slot 345,600,000, the first slot of epoch 800.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>passkeys</category>
      <category>webauthn</category>
    </item>
    <item>
      <title>Solana Honeypots That Pass Your Sell Simulation: How</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:17 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/solana-honeypots-that-pass-your-sell-simulation-how-123l</link>
      <guid>https://dev.to/sulimanmukhtar/solana-honeypots-that-pass-your-sell-simulation-how-123l</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-honeypot-simulation-aware-programs" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The careful trader’s routine: before buying a new token, simulate a sell. Build the swap back to SOL, run it through &lt;code&gt;simulateTransaction&lt;/code&gt;, confirm it succeeds. If the sell simulates, the token is not a honeypot. Buy.&lt;/p&gt;

&lt;p&gt;The routine has a hole, and some tokens are built to sit in it. A program can tell whether it is running inside a simulation or inside a real block, and behave differently in each. The sell succeeds on paper and reverts on chain, every time, for everyone. This post is the mechanism — it is in the validator’s own test suite — and what a check has to do instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  How a program knows it is being simulated
&lt;/h2&gt;

&lt;p&gt;When a node simulates a transaction, it runs it against a copy of the current state. For almost everything the program can see — accounts, balances, the clock — the simulation and the real execution are identical. For one thing they are not.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;SlotHistory&lt;/strong&gt; sysvar is a bitmap of which recent slots produced blocks. In real execution a program reads the sysvar as it stood when the block began. In simulation, the node substitutes its own version of that one account — it is the only account the simulation path overrides, and the source says so in a comment: no other overrides are expected. The substituted version is not quite the same shape as the one a block producer provides.&lt;/p&gt;

&lt;p&gt;The validator’s test corpus includes a program that does exactly this: it reads the SlotHistory account, finds its newest slot, and compares it with the slot in the Clock sysvar. The two relationships differ between simulation and execution, and the program branches on the difference. The test exists to make sure the detection keeps working, because tooling relies on it. It also hands anyone who reads the test suite a honeypot recipe.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the honeypot does with that bit
&lt;/h2&gt;

&lt;p&gt;The pattern is short. The token’s transfer logic — a Token-2022 transfer hook, or a custom program the pool routes through — checks the simulation flag. If simulated, allow the transfer. If real, fail it for any wallet that is not on the deployer’s list.&lt;/p&gt;

&lt;p&gt;Every sell simulation in the world passes. Every real sell fails. Explorers show successful simulated sells, bots report “sellable”, and the only transactions that ever execute are buys and the deployer’s own exits.&lt;/p&gt;

&lt;p&gt;Two smaller tricks sit alongside it, and they do not even need the simulation bit. Simulation uses a blockhash age six slots more conservative than a leader, so a program that reads the blockhash age can occasionally distinguish the two. And a program can simply read the Clock and behave differently after a fixed slot — a sell that works until launch day plus one epoch, then stops.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the static checks still matter
&lt;/h2&gt;

&lt;p&gt;The simulation-aware honeypot is the rare case. The common honeypot is still a configuration you can read without executing anything:&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;freeze authority&lt;/strong&gt; that can freeze your token account after you buy.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;transfer hook&lt;/strong&gt; program whose source you cannot read.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;pausable&lt;/strong&gt; or &lt;strong&gt;default-frozen&lt;/strong&gt; mint, or a &lt;strong&gt;permanent delegate&lt;/strong&gt; that can burn or move your balance.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;transfer fee&lt;/strong&gt; at or near 100%.&lt;/p&gt;

&lt;p&gt;A permissioned mint whose allowlist you are not on.&lt;/p&gt;

&lt;p&gt;Those are flags on the mint and its extensions, and &lt;a href="https://app.xroot.dev/token-audit?ref=blog" rel="noopener noreferrer"&gt;a static audit&lt;/a&gt; reads them in one account fetch. The audit page runs those reads and reports each one with what it means. What it cannot do, and does not claim to do, is execute your sell on chain — which is the only test the simulation-aware class fails.&lt;/p&gt;




&lt;h2&gt;
  
  
  The test that cannot be fooled
&lt;/h2&gt;

&lt;p&gt;Execution. A sell that is actually submitted and actually lands, for a wallet the deployer does not control, is the one check that no program can branch around — it runs in a real block with the real sysvar.&lt;/p&gt;

&lt;p&gt;That is expensive to do for every token and impossible before you hold any. The practical compromise: buy an amount you can lose, sell a fraction of it immediately in a real transaction, and only then size up. A sell that lands is evidence; a sell that simulates is a claim.&lt;/p&gt;

&lt;p&gt;The other signal is history. A token whose only successful sells belong to a handful of wallets, while hundreds of buys never produce a sell, has told you what the program does without you reading it. Address history with block positions makes that pattern visible, and it is the same data the sandwich post uses.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this post does not say
&lt;/h2&gt;

&lt;p&gt;It does not say the detection trick is common. Most tokens that cannot be sold are stopped by a freeze authority or a hook, and a static audit finds those. It does not say a passing simulation is worthless — a failing one is still a reliable refusal. And it does not say any page, including ours, can certify a token as sellable. A certificate would be a promise the mechanism cannot keep.&lt;/p&gt;




&lt;h2&gt;
  
  
  Honeypots: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can a Solana program detect that it is being simulated?
&lt;/h3&gt;

&lt;p&gt;Yes. Simulation substitutes one sysvar account, SlotHistory, and a program that compares it with the Clock sysvar can tell the two environments apart. The validator’s own test suite contains a program that does this.&lt;/p&gt;

&lt;h3&gt;
  
  
  My sell simulation passed. Is the token safe?
&lt;/h3&gt;

&lt;p&gt;Not necessarily. A simulation-aware program allows the sell in simulation and refuses it on chain. A passing simulation rules out the common honeypot configurations only if the static checks also pass, and a real sell is the only decisive test.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the safest way to test if I can sell a token?
&lt;/h3&gt;

&lt;p&gt;Sell a small amount in a real, submitted transaction before buying more. A sell that lands on chain cannot be faked by the program.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does the token audit catch simulation-aware honeypots?
&lt;/h3&gt;

&lt;p&gt;No. It reads the mint’s authorities, extensions, fee and hook configuration, which catches the ordinary cases. It does not execute a sell, and no static check can detect behaviour that only appears in a real block.&lt;/p&gt;




&lt;h2&gt;
  
  
  The order of checks
&lt;/h2&gt;

&lt;p&gt;Read the mint: authorities, extensions, fee, hook. Refuse on any of the flags above.&lt;/p&gt;

&lt;p&gt;Simulate the sell. Refuse on failure; treat success as necessary, not sufficient.&lt;/p&gt;

&lt;p&gt;Sell a fraction for real before you size up. That is the only step a program cannot see coming.&lt;/p&gt;

&lt;p&gt;— Most Traps Are Static —&lt;/p&gt;

&lt;h3&gt;
  
  
  Read the mint before you buy, then prove the exit with a real sell.
&lt;/h3&gt;

&lt;p&gt;The token audit reads the authorities, extensions and hooks that stop most unsellable tokens, straight from the chain. What it cannot see is a program that behaves differently when it is not being simulated — which is why the last check is a small real sell.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.xroot.dev/token-audit?ref=blog" rel="noopener noreferrer"&gt;Audit a Token ↗&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same blind spot has a sibling that needs no clever program at all — &lt;a href="https://xroot.dev/blog/solana-owner-reassignment-scam-wallet-simulator" rel="noopener noreferrer"&gt;owner reassignment&lt;/a&gt; — and the legitimate version of a frozen-until-approved token is &lt;a href="https://xroot.dev/blog/solana-permissioned-tokens-token-acl" rel="noopener noreferrer"&gt;Token ACL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;programs/sbf/rust/simulation/src/lib.rs&lt;/code&gt;, &lt;code&gt;svm/src/account_loader.rs&lt;/code&gt; and &lt;code&gt;runtime/src/bank.rs&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>security</category>
      <category>honeypots</category>
    </item>
    <item>
      <title>The Solana Scam a Wallet Simulator Cannot See: Assign</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:15 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/the-solana-scam-a-wallet-simulator-cannot-see-assign-fmj</link>
      <guid>https://dev.to/sulimanmukhtar/the-solana-scam-a-wallet-simulator-cannot-see-assign-fmj</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-owner-reassignment-scam-wallet-simulator" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Your wallet simulates every transaction before you sign. It shows the SOL going out, the tokens coming in, the accounts touched. You have been told, correctly, to read that preview and refuse anything that drains you.&lt;/p&gt;

&lt;p&gt;There is an instruction that drains you and shows nothing. No balance changes. No tokens move. The preview reads “no balance change”, you sign, and from that moment your account belongs to someone else’s program. In December 2025 SlowMist &lt;a href="https://en.coinotag.com/breakingnews/solana-phishing-attack-replaces-owner-permission-over-3m-stolen-and-2m-recovered-slowmist-security-advisory" rel="noopener noreferrer"&gt;reported a case&lt;/a&gt; in which one signature with no visible balance change replaced a victim’s owner permission: more than $3 million was drained, and about $2 million held inside a DeFi position was later recovered with that protocol’s help.&lt;/p&gt;

&lt;p&gt;The instruction is &lt;code&gt;Assign&lt;/code&gt;, in the System program. Here is what it does, why simulators are blind to it, and the one check that catches it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Every Solana account has an owner, and the owner is the only writer
&lt;/h2&gt;

&lt;p&gt;An account on Solana is a balance, some data, and an &lt;strong&gt;owner&lt;/strong&gt; — the program allowed to modify the data and debit the balance. Your wallet’s main account is owned by the System program, which is why the System program’s &lt;code&gt;Transfer&lt;/code&gt; instruction can move your SOL when you sign. A token account is owned by the token program; a stake account by the stake program.&lt;/p&gt;

&lt;p&gt;The rule the runtime enforces is strict: only the owning program can change an account’s data or reduce its lamports. Any other program may read it and may add lamports to it, nothing more.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Assign&lt;/code&gt; changes the owner. It is a legitimate instruction — every program-derived account starts life as a System account and is assigned to its program — and it requires the account’s signature. Your signature. Which is exactly what a phishing transaction asks for.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the preview says “no balance change”
&lt;/h2&gt;

&lt;p&gt;Wallet simulators run the transaction and diff the result: lamports before and after, token balances before and after. &lt;code&gt;Assign&lt;/code&gt; changes neither. The account holds the same SOL after the instruction as before. The diff is empty, and the preview says so, in the reassuring green that every simulator uses for a transaction that costs you nothing.&lt;/p&gt;

&lt;p&gt;The preview is not lying. It is answering the wrong question. “Did my balance change” is the question for a transfer. The question for &lt;code&gt;Assign&lt;/code&gt; is “can I still move this balance”, and no simulator asks it, because the answer is not a balance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth knowing:&lt;/strong&gt; an &lt;code&gt;Assign&lt;/code&gt; that sets the owner to the owner the account already has is a no-op the program accepts without even checking for a signature. A transaction that includes one is odd, but harmless. The dangerous one names a program you do not control.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What you can and cannot do afterwards
&lt;/h2&gt;

&lt;p&gt;After the reassignment, the account’s SOL is still there and still yours in every sense except the one that matters.&lt;/p&gt;

&lt;p&gt;You cannot transfer it. The System program’s &lt;code&gt;Transfer&lt;/code&gt; requires the source to be a System-owned account, and will also refuse any account that carries data. Your account now has a different owner, and whichever program that is decides what happens to the lamports.&lt;/p&gt;

&lt;p&gt;You cannot reassign it back. &lt;code&gt;Assign&lt;/code&gt; requires the current owner program’s cooperation, and the attacker’s program will not give it.&lt;/p&gt;

&lt;p&gt;You cannot close it, or recover its rent, or use it as a fee payer in any transaction that touches its balance.&lt;/p&gt;

&lt;p&gt;The attacker’s program, meanwhile, can debit the account at will, which is how the SOL leaves. Tokens held in your wallet’s token accounts are a separate matter: those accounts are owned by the token program, and &lt;code&gt;Assign&lt;/code&gt; on your main account does not touch them. But the same phishing transaction routinely includes a token &lt;code&gt;SetAuthority&lt;/code&gt; on each of them, changing the authority to the attacker — a different instruction, the same empty preview.&lt;/p&gt;




&lt;h2&gt;
  
  
  The one check
&lt;/h2&gt;

&lt;p&gt;Read the owner. &lt;code&gt;getAccountInfo&lt;/code&gt; returns it for any address. For a wallet’s main account it must be the System program, &lt;code&gt;11111111111111111111111111111111&lt;/code&gt;. For a token account it must be the token program, and the authority recorded inside the account’s data must be your wallet.&lt;/p&gt;

&lt;p&gt;If either has changed, the account is no longer yours to operate, and no amount of revoking or re-signing fixes it. Move what can still be moved — tokens in accounts whose authority is still you, SOL in accounts still owned by the System program — and treat the reassigned account as gone.&lt;/p&gt;

&lt;p&gt;Before you sign, the check is different: read the instruction list, not the balance diff. An &lt;code&gt;Assign&lt;/code&gt; naming an unfamiliar program, or a &lt;code&gt;SetAuthority&lt;/code&gt; on any of your token accounts, is a refusal regardless of what the preview says. Most wallets now flag these; the campaign in January is why.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this post cannot offer
&lt;/h2&gt;

&lt;p&gt;A fix. There is none. A reassigned account cannot be reclaimed by its former owner, and any page that offers to “recover” such an account is either describing something else or is the next scam. What exists is prevention — read the instructions, not the diff — and limitation: keep the balance you cannot afford to lose in an account you do not sign transactions from.&lt;/p&gt;

&lt;p&gt;The sibling hazard is the pre-signed transaction that never expires, which is a different mechanism with the same lesson: the decisive moment is signing, and the simulator is not the judge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Owner Reassignment: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What does the System program’s Assign instruction do?
&lt;/h3&gt;

&lt;p&gt;It changes an account’s owner to another program. Only the owning program can modify an account’s data or reduce its balance, so after an Assign the previous owner cannot move the SOL in it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did my wallet’s simulation show no balance change?
&lt;/h3&gt;

&lt;p&gt;Because Assign does not move lamports or tokens. Simulators diff balances, and the diff is empty. The harm is a change of control, which a balance diff cannot show.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I get a reassigned Solana account back?
&lt;/h3&gt;

&lt;p&gt;No. Reassigning requires the current owner program’s cooperation. Move anything that is still under your control and treat the reassigned account as lost.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I check whether my accounts are still mine?
&lt;/h3&gt;

&lt;p&gt;Call getAccountInfo and read the owner. A wallet’s main account must be owned by the System program; a token account by the token program, with your wallet as the authority inside its data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two rules
&lt;/h2&gt;

&lt;p&gt;A preview that shows no balance change is not a preview that shows no harm. Read the instructions.&lt;/p&gt;

&lt;p&gt;Check your accounts’ owners today. It is one RPC call per account, the answer is a program id, and for a wallet it must be the System program. If it is anything else, the account is not yours any more, and the time to find out is before you need it.&lt;/p&gt;

&lt;p&gt;Its closest relative is &lt;a href="https://xroot.dev/blog/solana-durable-nonce-pre-signed-transactions" rel="noopener noreferrer"&gt;a signed transaction that never expires&lt;/a&gt;, and its counterpart on the token side is &lt;a href="https://xroot.dev/blog/solana-honeypot-simulation-aware-programs" rel="noopener noreferrer"&gt;a honeypot that passes your simulation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;programs/system/src/system_processor.rs&lt;/code&gt; and the &lt;code&gt;transaction-context&lt;/code&gt; crate.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>security</category>
      <category>walletdrainers</category>
    </item>
    <item>
      <title>Solana Vanity Addresses: What a Prefix Really Costs</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 10:07:14 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/solana-vanity-addresses-what-a-prefix-really-costs-2mcn</link>
      <guid>https://dev.to/sulimanmukhtar/solana-vanity-addresses-what-a-prefix-really-costs-2mcn</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-vanity-address-grinder-odds" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You want a wallet address that starts with your name, or a token mint that starts with the ticker. It is a real thing people do, the tool to do it ships with the Solana CLI, and the maths behind it fits on one line. Here is how the grinder works, how many tries a prefix costs, the two safety rules that matter, and the reason a matching prefix should never be mistaken for a matching address.&lt;/p&gt;




&lt;h2&gt;
  
  
  What an address is
&lt;/h2&gt;

&lt;p&gt;A Solana address is 32 random bytes — a public key — written in base58. Base58 is the alphabet of digits and letters with four characters removed because they look like each other: zero, capital O, capital I and lowercase l. That leaves &lt;strong&gt;58&lt;/strong&gt; characters, and 32 bytes come out as 43 or 44 of them.&lt;/p&gt;

&lt;p&gt;There is no “choosing” an address. You generate a random private key, derive its public key, and look at the characters. A vanity address is a random key whose public key happened to start with what you wanted, found by generating keys until one does. The grinder is a loop.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth knowing:&lt;/strong&gt; the smallest possible 44-character address is the one the tool keeps as a constant — a 2 followed by forty-three 1s. Not every string is reachable: a prefix that would decode to more than 32 bytes cannot exist, and the tool skips candidates above that bound before it bothers encoding them.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The grinder
&lt;/h2&gt;

&lt;p&gt;The tool is &lt;code&gt;solana-keygen grind&lt;/code&gt;. It takes three kinds of target, each as the pattern and a count of how many matching keys you want:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--starts-with xroot:1&lt;/code&gt; — one key whose address begins with &lt;code&gt;xroot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--ends-with 1234:1&lt;/code&gt; — one key whose address ends with &lt;code&gt;1234&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--starts-and-ends-with ab:cd:1&lt;/code&gt; — both.&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;--ignore-case&lt;/code&gt; to accept any capitalisation of the letters, and &lt;code&gt;--num-threads&lt;/code&gt; to use more cores. Every thread generates random keypairs, encodes the public key, and checks it against every target until the counts are filled. When a match is found the keypair is written to a file named after the address.&lt;/p&gt;

&lt;p&gt;That is the whole algorithm. There is no shortcut, no table, no way to steer the key toward a prefix. Each try is independent and each has the same tiny chance.&lt;/p&gt;




&lt;h2&gt;
  
  
  The odds, in tries
&lt;/h2&gt;

&lt;p&gt;Each character position in a base58 address is close to uniform over 58 values, so a case-sensitive prefix of &lt;em&gt;n&lt;/em&gt; characters matches one key in 58ⁿ on average:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1 character&lt;/strong&gt; — 58 tries&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; — 3,364&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; — 195,112&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt; — about 11.3 million&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; — about 656 million&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt; — about 38 billion&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7&lt;/strong&gt; — about 2.2 trillion&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--ignore-case&lt;/code&gt; helps by roughly the number of letters in the prefix that have both cases: a five-letter all-alphabetic prefix with case ignored is about 2⁵ = 32 times cheaper — twenty million tries instead of 656 million.&lt;/p&gt;

&lt;p&gt;How long that takes depends entirely on your hardware, and the tool shows its progress rather than promising a rate. The useful rule is the ratio: each extra character multiplies the work by 58, each case-insensitive letter divides it by about 2. Four characters is minutes on a laptop; six is a serious machine for a long time; eight is not a thing people do for a wallet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two safety rules
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Never use a website or a service to grind a key.&lt;/strong&gt; Whatever generates the keypair holds the keypair. A vanity address from a web generator is an address someone else can empty, and the pattern of “cheap vanity address, drained later” is old. Run the tool yourself, on your own machine, offline if the key will hold anything.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The output file is plain text.&lt;/strong&gt; &lt;code&gt;solana-keygen&lt;/code&gt; writes the keypair as a plain JSON array of bytes. If you generate with a recovery phrase and a passphrase, the passphrase protects the phrase, not the file — the tool’s own source describes the file as stored as insecure plain text. Treat the file the way you would treat a seed phrase written on paper, and note that the tool refuses &lt;code&gt;--no-outfile&lt;/code&gt; unless you also asked for a mnemonic, so a key can never be generated with no recovery path at all.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The reason a prefix is not an identity
&lt;/h2&gt;

&lt;p&gt;This is the part that matters more than the odds. If you can grind an address that starts with &lt;code&gt;xroot&lt;/code&gt;, so can anyone else. Address poisoning attacks do exactly that: generate an address whose first and last characters match a victim’s real counterparty, send a dust transfer so it appears in the victim’s history, and wait for the victim to copy the lookalike from the list.&lt;/p&gt;

&lt;p&gt;A vanity prefix on your own address makes you easier to recognise and easier to imitate in the same move. The defence is the same as for any address: verify the whole string, or a long enough suffix as well as the prefix, and never copy an address out of a transaction history. The grinder that makes vanity addresses possible is the grinder that makes the poisoning cheap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Vanity Addresses: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I generate a Solana vanity address?
&lt;/h3&gt;

&lt;p&gt;With the CLI: solana-keygen grind --starts-with PREFIX:1, optionally --ignore-case and --num-threads N. The tool generates random keypairs until one’s public key matches, then writes the keypair file.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long does a vanity address take?
&lt;/h3&gt;

&lt;p&gt;On average 58 to the power of the prefix length tries for a case-sensitive prefix: about 11 million for four characters, 656 million for five, 38 billion for six. --ignore-case divides that by roughly two per letter. Actual time depends on your hardware.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are vanity addresses safe?
&lt;/h3&gt;

&lt;p&gt;Only if you generate them yourself, offline, and guard the plain-text keypair file. Any service that generates the key for you holds the key. A vanity prefix also makes your address easier to imitate in address-poisoning attacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can two wallets have the same vanity prefix?
&lt;/h3&gt;

&lt;p&gt;Yes, and that is the risk. Anyone can grind a prefix. Verify the entire address, never just the start, before sending.&lt;/p&gt;




&lt;h2&gt;
  
  
  If you are going to do it
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;solana-keygen grind&lt;/code&gt; locally, with &lt;code&gt;--ignore-case&lt;/code&gt; if the capitalisation does not matter to you, and keep the prefix to four or five characters unless you have the hardware for more.&lt;/p&gt;

&lt;p&gt;Treat the output file as the key itself, because it is.&lt;/p&gt;

&lt;p&gt;Tell the people who send you money to check the full address, not the start of it. Your prefix is the easiest part of your address to fake.&lt;/p&gt;

&lt;p&gt;A familiar-looking prefix is exactly what drainers rely on — &lt;a href="https://xroot.dev/blog/solana-owner-reassignment-scam-wallet-simulator" rel="noopener noreferrer"&gt;owner reassignment&lt;/a&gt; is one of them — and a keypair that must stay offline signs more safely with &lt;a href="https://xroot.dev/blog/solana-durable-nonce-pre-signed-transactions" rel="noopener noreferrer"&gt;a durable nonce&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Constants read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;keygen/src/keygen.rs&lt;/code&gt; and &lt;code&gt;clap-v3-utils/src/keygen/mnemonic.rs&lt;/code&gt;. Flag names change between releases — check them against &lt;code&gt;solana-keygen grind --help&lt;/code&gt; for the version you run.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>keys</category>
      <category>security</category>
    </item>
    <item>
      <title>Arc Chain, in Numbers: One Dollar, Two Decimals, and 97,000 Tokens in a Day</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Sun, 20 Sep 2026 02:50:10 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/arc-chain-in-numbers-one-dollar-two-decimals-and-97000-tokens-in-a-day-4b5o</link>
      <guid>https://dev.to/sulimanmukhtar/arc-chain-in-numbers-one-dollar-two-decimals-and-97000-tokens-in-a-day-4b5o</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/arc-chain-in-numbers" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Circle opened Arc's public mainnet on 16 September 2026. Four days later I read it the way I read every new chain — from its own node, with &lt;code&gt;eth_call&lt;/code&gt;, ignoring the launch posts. Six numbers came back that the launch posts do not carry, and two of them will bite anyone who integrates the chain from a table instead of a query.&lt;/p&gt;

&lt;p&gt;The headline facts hold up: an EVM layer 1 whose native coin is USDC, blocks every half second, deterministic finality, and a validator set of twelve named institutions — Circle plus BlackRock, DTCC, Visa, Mastercard, ICE and six more — running proof of authority. Everything that follows is what the chain itself says, read on 20 September at block 21,767,062, with the call that produced each figure so you can run it again.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ground Truth in Four Calls
&lt;/h2&gt;

&lt;p&gt;A chain id gets transcribed wrong, an RPC URL goes stale, and "mainnet is live" means at least four different things. So: ask the node.&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;RPC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://rpc.mainnet.arc.io
call&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nv"&gt;$RPC&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

call &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; 0x13b2 = 5042&lt;/span&gt;

call &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"web3_clientVersion","params":[]}'&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; "arc/v1"            (a Reth-based client under a Malachite BFT consensus)&lt;/span&gt;

call &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"eth_getBlockByNumber","params":["latest",false]}'&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; gasLimit 0x1c9c380 = 30,000,000 · gasUsed 213,828 · 4 transactions&lt;/span&gt;
&lt;span class="c"&gt;#    baseFeePerGas 0x4a817c800 = 20 gwei · extraData 0x00000004a817c800&lt;/span&gt;

call &lt;span class="s1"&gt;'{"jsonrpc":"2.0","id":1,"method":"eth_getCode","params":["0x000000000000000000000000000000000000006b","latest"]}'&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; 0x                   (no Arbitrum precompile: this is not a Nitro chain)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Chain ID&lt;/strong&gt; — 5042 (0x13b2)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt; — Malachite BFT + Reth · Osaka EVM · L1&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Block&lt;/strong&gt; — ~0.5 s · 30M gas · 3–11% used&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gas coin&lt;/strong&gt; — USDC · base fee pinned at 20 gwei&lt;/p&gt;

&lt;p&gt;The last line of the block header is the interesting one. &lt;code&gt;extraData&lt;/code&gt; is eight bytes, and it equals the base fee: Arc publishes the &lt;em&gt;next&lt;/em&gt; block's base fee in the parent header. That is a fee market telling you its answer before you ask, and it is the subject of section three.&lt;/p&gt;

&lt;p&gt;Multicall3, Permit2, the CREATE2 deterministic deployer and Safe v1.4.1 are all present at their canonical addresses. The MetaMask, Alchemy and Uniswap EIP-7702 delegator contracts hold code too; the docs put the EVM at the Osaka fork, which is what makes delegating to them possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  One Dollar, Two Decimals
&lt;/h2&gt;

&lt;p&gt;USDC is the native coin. That sentence hides a detail every integrator will trip on once: the node counts it in &lt;strong&gt;18 decimals&lt;/strong&gt;, and the ERC-20 contract that represents the same coin counts it in &lt;strong&gt;6&lt;/strong&gt;. Same balance, two scales, a factor of a trillion apart.&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;POOL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x8366a39cc670b4001a1121b8f6a443a643e40951   &lt;span class="c"&gt;# Uniswap v4 PoolManager&lt;/span&gt;
&lt;span class="nv"&gt;USDC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x3600000000000000000000000000000000000000   &lt;span class="c"&gt;# the ERC-20 face of the native coin&lt;/span&gt;
&lt;span class="nv"&gt;BLOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x14c2602                                    &lt;span class="c"&gt;# pin both reads to one block&lt;/span&gt;

&lt;span class="c"&gt;# The native balance, as the node counts it: 18 decimals&lt;/span&gt;
eth_getBalance&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$POOL&lt;/span&gt;, &lt;span class="nv"&gt;$BLOCK&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; 3,692,022,800,475,000,000,000  wei-equivalent&lt;/span&gt;
&lt;span class="c"&gt;#    ÷ 1e12 = 3,692,022,800,475&lt;/span&gt;

&lt;span class="c"&gt;# The ERC-20 balance, as the contract counts it: 6 decimals&lt;/span&gt;
eth_call&lt;span class="o"&gt;({&lt;/span&gt; to: &lt;span class="nv"&gt;$USDC&lt;/span&gt;, data: balanceOf&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$POOL&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;, &lt;span class="nv"&gt;$BLOCK&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; 3,692,022,800,475&lt;/span&gt;
&lt;span class="c"&gt;#    = $3,692,022.800475&lt;/span&gt;

&lt;span class="c"&gt;# decimals() on the face -&amp;gt; 6 · symbol() -&amp;gt; "USDC" · name() -&amp;gt; "USDC"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the same block the two numbers agree to the unit, so this is one balance with two interfaces, not a coin and a wrapper. The contract at &lt;code&gt;0x3600…0000&lt;/code&gt; also emits &lt;code&gt;Transfer&lt;/code&gt; events for native movements — four of them in the block I pinned — which is EIP-7708 in practice: a history indexer that reads native sends &lt;em&gt;and&lt;/em&gt; those logs counts every transfer twice.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;nativeCurrency.decimals: 18&lt;/code&gt; is chain precision, not display precision.&lt;/strong&gt; A wallet that adds the network from the standard parameters and trusts the decimals field will show a one-dollar balance as &lt;code&gt;0.000000000001&lt;/code&gt;. Arc's own wallet guide says to divide by 10¹², label the result USDC rather than ETH, and merge the native and ERC-20 rows into one — and the network-parameters page warns that a wallet without custom-gas-token support "may display balances as ETH".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One more read on that contract, because it is where Circle's controls would live if they lived in code. The ERC-20 face is 1,798 bytes, is not a proxy (the EIP-1967 implementation slot is empty), and its bytecode contains none of the selectors the mainnet USDC contract is known for — &lt;code&gt;blacklist&lt;/code&gt;, &lt;code&gt;isBlacklisted&lt;/code&gt;, &lt;code&gt;pause&lt;/code&gt;, &lt;code&gt;mint&lt;/code&gt;. That does not mean there is no freeze on Arc; it means the freeze, if it exists, is not in this contract. The honest reading stops there.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Fee Floor, Not a Fee Market
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;eth_feeHistory&lt;/code&gt; over the last blocks returns the same base fee six times: 20 gwei, with utilisation between three and eleven percent. Arc's fee model is EIP-1559 with a moving average on top and a hard floor — 20 gwei in the docs, and 20 gwei in every block I sampled — so under normal load the base fee never moves. It sits on the floor. The node's suggested price was 22.0 gwei, of which 2.0 was tip.&lt;/p&gt;

&lt;p&gt;Now do the unit conversion nobody does. The native coin is a dollar, and one gwei is 10⁻⁹ of it. So a gas unit costs two hundredths of a millionth of a cent, and at the 22.0 gwei the node suggested that morning:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plain transfer · 21,000 gas&lt;/strong&gt; — $0.00046&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ERC-20 transfer · ~65,000 gas&lt;/strong&gt; — $0.0014&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uniswap v4 fee claim · ~250,000 gas&lt;/strong&gt; — $0.0055&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token deployment · ~2,000,000 gas&lt;/strong&gt; — $0.044&lt;/p&gt;

&lt;p&gt;Two things follow. First, a fee quote on this chain is a solved problem: the price is pinned, denominated in dollars, and needs no oracle — the number on screen is the number, every time. Second, gas cannot be anyone's business model here, including the chain's. At 1.5 million transactions a day and a typical cost under a tenth of a cent, the network's whole daily gas take is on the order of a thousand dollars (an estimate from those two figures, not a measurement). Whatever pays for twelve SOC 2 validators, it is not the fee floor.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Wrapped Token That Only Reverts
&lt;/h2&gt;

&lt;p&gt;Every Uniswap deployment carries a &lt;code&gt;WETH9&lt;/code&gt; address — the wrapped native coin the routers and position managers use when a pool holds ETH. Ask Arc's v4 PositionManager for it and you get an answer. Ask the answer anything and you get a revert:&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;PM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x6049c9a0e26405c0985f9e3685c87d0ae917f82b     &lt;span class="c"&gt;# Uniswap v4 PositionManager&lt;/span&gt;

eth_call&lt;span class="o"&gt;({&lt;/span&gt; to: PM, data: WETH9&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; 0x8bceaa40b9acdfaedf85adf4ff01f5ad6517937f&lt;/span&gt;

eth_getCode&lt;span class="o"&gt;(&lt;/span&gt;0x8bceaa40…937f&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; 53 bytes:&lt;/span&gt;
&lt;span class="c"&gt;#    6080604052 348015600e575f5ffd5b50   ; standard prologue, no value&lt;/span&gt;
&lt;span class="c"&gt;#    60405163 ea3559ef 60e01b 8152 6004 01 ; PUSH4 0xea3559ef … REVERT&lt;/span&gt;
&lt;span class="c"&gt;#    …fd&lt;/span&gt;

eth_call&lt;span class="o"&gt;({&lt;/span&gt; to: 0x8bceaa40…937f, data: name&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;      -&amp;gt; revert 0xea3559ef
eth_call&lt;span class="o"&gt;({&lt;/span&gt; to: 0x8bceaa40…937f, data: symbol&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;    -&amp;gt; revert 0xea3559ef
eth_call&lt;span class="o"&gt;({&lt;/span&gt; to: 0x8bceaa40…937f, data: decimals&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;  -&amp;gt; revert 0xea3559ef
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not a squatter and not a bug. Uniswap's own deployment table for chain 5042 lists the address as &lt;em&gt;"Unsupported Protocol (WETH9)"&lt;/em&gt;: a 53-byte contract whose only behaviour is to revert with one custom error, deployed on purpose so that every code path expecting a wrapper fails loudly instead of silently. On Arc there is nothing to wrap — the native coin already has an ERC-20 face at &lt;code&gt;0x3600…0000&lt;/code&gt;. Any "wrap" or "unwrap" button, any router path that hops through WETH, any collect-and-compound flow that calls &lt;code&gt;deposit()&lt;/code&gt; — all of it dies here, and it dies with a selector you can grep for.&lt;/p&gt;

&lt;p&gt;The squatter &lt;em&gt;is&lt;/em&gt; elsewhere, and it is the same one I found on &lt;a href="https://xroot.dev/blog/robinhood-chain-read-directly" rel="noopener noreferrer"&gt;Robinhood Chain in August&lt;/a&gt;. Uniswap v3's canonical mainnet addresses — &lt;code&gt;0x1F98…F984&lt;/code&gt; for the factory, &lt;code&gt;0xC364…FE88&lt;/code&gt; for the position manager — both hold a 2,747-byte contract on Arc that is not Uniswap v3. &lt;code&gt;feeAmountTickSpacing(3000)&lt;/code&gt; returns nothing. The real v3 factory is at &lt;code&gt;0xf0db…3918&lt;/code&gt; and answers 60, and its position manager at &lt;code&gt;0x3965…1377&lt;/code&gt; points back to it. A tool that copies v3 addresses from a table it trusts would be reading a stranger's contract and calling it Uniswap. Read the code, make one live call, then believe the address.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Got There First
&lt;/h2&gt;

&lt;p&gt;Arc was built, in Circle's words, for payments, FX, tokenised assets and institutional markets. The explorer's daily transaction chart says who actually showed up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;12–15 September, private mainnet:&lt;/strong&gt; 126K · 131K · 407K · 456K transactions a day.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;16 September, public launch:&lt;/strong&gt; &lt;strong&gt;7,763,670&lt;/strong&gt; transactions. Reporters counted 97,025 new tokens that day, more than 83,000 of them through one launchpad, and $410.8M of trading with about 82% from memecoin launchpads.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;17 · 18 · 19 September:&lt;/strong&gt; 5,472,100 · 2,611,050 · 1,551,810. Down 80% from the launch day in three days.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The DEX numbers from DefiLlama on 20 September: $52.8M in the last day, of which Uniswap v4 is $36.8M and v3 $14.4M — 97% between them. The v4 PositionManager's &lt;code&gt;nextTokenId&lt;/code&gt; reads 222,177, so 222,176 v4 positions have been minted so far; the v3 manager's &lt;code&gt;totalSupply&lt;/code&gt; is 36,325. Total protocol fees on the chain, all sources, were $375K in the same day. For scale, Robinhood Chain booked roughly forty-five times that on the day I measured it in early September.&lt;/p&gt;

&lt;p&gt;The explorer counts 1,316,279 contracts on the chain and 19,380 verified ones — one in sixty-eight. And the trending list on the pool indexer, the morning I looked, had this in it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;USDC / USDC 1%&lt;/code&gt; — $1.16M traded in 24 hours, $386K in reserve, on a launchpad's own exchange.&lt;/strong&gt; A token that calls itself USDC, paired against the real one. On Arc exactly one address is USDC: &lt;code&gt;0x3600…0000&lt;/code&gt;. EURC is one address. USYC is one address. A ticker is a string anyone can type into a constructor; the address is the only thing a copy cannot have. GoPlus was already warning about clones of two of the chain's biggest launch tokens by the second day.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I do not read the decay as a verdict. A launch-day spike that falls 80% is the shape of every launch; the question is where the line flattens, and four days do not answer it. What the numbers do say is that the population using Arc today is the one that uses every new EVM chain in its first week — launching, trading and copying tokens — and it arrived before the institutional use the chain was named for.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Token That Exists and Is Not Launched, and Who Runs the Chain
&lt;/h2&gt;

&lt;p&gt;On launch day Circle announced a genesis mint of &lt;strong&gt;10 billion ARC&lt;/strong&gt; tokens — and, in the same breath, that they are not available to the public and that the mint is "a technical milestone, not a commitment to launch". The whitepaper post on arc.io still carries the line that any token "is merely exploratory". Gas stays in USDC. A move to proof of stake, where the token would have a job, is described as something Circle is exploring for 2027.&lt;/p&gt;

&lt;p&gt;So: the token exists on-chain and has no holders you can become. Anything trading under that ticker today, and anything offering an "ARC airdrop" or an "ARC claim", is not Circle's. Search interest in "arc token" hit its peak on launch day, which is exactly the audience those pages are built for.&lt;/p&gt;

&lt;p&gt;Who runs the chain is disclosed more plainly than most. Twelve named institutions run proof of authority; a block is final when more than two thirds of them pre-commit to it; Circle chose them. Arc's security page says that "validator-layer sanctions controls are part of Arc's network operating model" and names a third-party monitoring provider. On Robinhood Chain I could count how often the filtering switch had been used, because Nitro exposes the filterer as a precompile with a public nonce. Arc is not Nitro and has no such artefact, so whether the switch has been thrown is not something the chain will tell you. I record that as an unknown, not as an absence.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to Carry Out of This
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Decimals come from the asset, never from the chain.&lt;/strong&gt; Read &lt;code&gt;decimals()&lt;/code&gt; on the ERC-20 face and treat native units as 18; divide by 10¹² to show dollars. The two are one balance.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;There is no WETH.&lt;/strong&gt; The address Uniswap points at reverts by design. Delete the wrap path; it has nothing to wrap.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Canonical addresses are not addresses.&lt;/strong&gt; The v3 factory is not where the tables say. Check code size and make one call the real contract must answer before you label anything.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The name is not the coin.&lt;/strong&gt; One address is USDC. Anything else wearing the ticker is a copy, and the first week's trending list already had one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Free tool&lt;/p&gt;

&lt;h3&gt;
  
  
  Is that token what it says it is?
&lt;/h3&gt;

&lt;p&gt;The token audit reads a contract's owner levers, hidden spenders, holders and liquidity straight from the chain — public data, no wallet connect, nothing to sign — and on Robinhood Chain checks a stock token against its issuer's own registry, so a copy is named as a copy. Solana and Robinhood Chain today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.xroot.dev/token-audit" rel="noopener noreferrer"&gt;Run a token audit&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the Source Yourself
&lt;/h2&gt;

&lt;p&gt;Every on-chain figure above came from the public endpoint &lt;code&gt;https://rpc.mainnet.arc.io&lt;/code&gt;, the chain's &lt;a href="https://explorer.arc.io" rel="noopener noreferrer"&gt;Blockscout explorer&lt;/a&gt; and its &lt;code&gt;/api/v2/stats&lt;/code&gt;, and &lt;a href="https://defillama.com/chain/arc" rel="noopener noreferrer"&gt;DefiLlama&lt;/a&gt;, all read on 20 September 2026. Reference: &lt;a href="https://docs.arc.io/arc/references/connect-to-arc" rel="noopener noreferrer"&gt;Arc network parameters&lt;/a&gt;, &lt;a href="https://docs.arc.io/arc/references/gas-and-fees" rel="noopener noreferrer"&gt;the fee model&lt;/a&gt;, &lt;a href="https://www.arc.io/blog/supporting-arc-in-wallets-one-balance-usdc-fees-and-complete-history" rel="noopener noreferrer"&gt;Arc's wallet integration guide&lt;/a&gt;, &lt;a href="https://github.com/Uniswap/contracts/blob/main/deployments/5042.md" rel="noopener noreferrer"&gt;Uniswap's deployment table for chain 5042&lt;/a&gt;, &lt;a href="https://www.arc.io/security" rel="noopener noreferrer"&gt;Arc's security page&lt;/a&gt;, and &lt;a href="https://www.circle.com/pressroom/circle-launches-arc-mainnet-an-economic-operating-system-for-the-internet" rel="noopener noreferrer"&gt;Circle's launch release&lt;/a&gt;. The launch-day token and volume counts are reporters' figures (BeInCrypto, CryptoRank, 17 September), not mine; the GoPlus warning was carried by KuCoin's news feed the same day. Re-run every call before relying on any of it — this chain is four days old.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;xroot.dev is not affiliated with, endorsed by, or sponsored by Circle Internet Group, Inc. "Arc", "USDC" and "EURC" are used here only to name the public blockchain and the assets this article examines. Nothing here is financial advice.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>arc</category>
      <category>evm</category>
      <category>stablecoins</category>
      <category>forensics</category>
    </item>
    <item>
      <title>After the Rent Cut, Your Old Solana Accounts Are Over-Funded</title>
      <dc:creator>Suliman Mokhtar</dc:creator>
      <pubDate>Fri, 18 Sep 2026 15:33:21 +0000</pubDate>
      <link>https://dev.to/sulimanmukhtar/after-the-rent-cut-your-old-solana-accounts-are-over-funded-2a5m</link>
      <guid>https://dev.to/sulimanmukhtar/after-the-rent-cut-your-old-solana-accounts-are-over-funded-2a5m</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://xroot.dev/blog/solana-rent-surplus-nonce-stake-vote-accounts" rel="noopener noreferrer"&gt;xroot.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://xroot.dev/blog/solana-rent-cut-simd-0437" rel="noopener noreferrer"&gt;rent-cut post&lt;/a&gt; explained the economics: Solana is cutting the price of account storage by 90% in five feature-gated steps, and accounts funded at the old price keep every lamport they were funded with. The follow-up question arrived within a day of publishing it: &lt;em&gt;if my account holds more rent than it now needs, can I get the difference back without closing it?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For four kinds of account, yes. Here is the arithmetic per type, the instruction that withdraws it, the switch that could put the price back up, and a detail from last week that will trip anyone tracking this by feature ID.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Formula, and Where the Ladder Stands
&lt;/h2&gt;

&lt;p&gt;Rent on Solana is now a single multiplication: &lt;strong&gt;(128 + data length) × lamports per byte&lt;/strong&gt;. The 128 is a fixed per-account overhead; the two-year multiplier that used to complicate this was folded into the byte price earlier this year.&lt;/p&gt;

&lt;p&gt;The byte price is stepping down through five gates:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ladder, lamports per byte&lt;/strong&gt; — 6,960 → 6,333 → 5,080 → 2,575 → 1,322 → 696&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mainnet on 17 September 2026&lt;/strong&gt; — step two — 5,080 since 11 September, a 27% cut&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Surplus against the original price&lt;/strong&gt; — (128 + length) × 1,880 lamports&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Surplus at the final step&lt;/strong&gt; — (128 + length) × 6,264 lamports&lt;/p&gt;

&lt;p&gt;Three steps remain, expected with Agave 4.4. At the end, the surplus is nine-tenths of what was originally deposited.&lt;/p&gt;




&lt;h2&gt;
  
  
  Four Account Types, Four Numbers
&lt;/h2&gt;

&lt;p&gt;Per account, today against the original price, and at the last step:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nonce account · 80 bytes&lt;/strong&gt; — ~0.00039 SOL now · ~0.0013 SOL at the end&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stake account · 200 bytes&lt;/strong&gt; — ~0.00062 SOL now · ~0.0021 SOL at the end&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vote account · 3,762 bytes&lt;/strong&gt; — ~0.0073 SOL now · ~0.024 SOL at the end&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token account · 165 bytes&lt;/strong&gt; — ~0.00055 SOL now · ~0.0018 SOL at the end&lt;/p&gt;

&lt;p&gt;Individually small. Multiplied by the number of accounts a wallet, a treasury or a validator operator controls, not small. A validator with a hundred nonce accounts for a signing pipeline, a distribution program that created ten thousand stake accounts, a market maker with a thousand token accounts: the surplus is a line item, and it grows at every step.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth knowing:&lt;/strong&gt; the surplus only exists for accounts created &lt;strong&gt;before&lt;/strong&gt; a step. Everything created after the final step holds the final price and has nothing to reclaim. The stock of over-funded accounts is fixed the day the ladder finishes, and it only shrinks as people notice.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Instruction Per Type, and Who Can Sign It
&lt;/h2&gt;

&lt;p&gt;Each program guards its own accounts, so the withdrawal is four different instructions with one rule in common: the account keeps at least the current rent-exempt minimum, and the signer is the account's own authority.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Nonce accounts:&lt;/strong&gt; &lt;code&gt;WithdrawNonceAccount&lt;/code&gt;, signed by the nonce authority, any amount above the rent-exempt minimum.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Stake accounts:&lt;/strong&gt; the stake program's &lt;code&gt;Withdraw&lt;/code&gt;, signed by the withdraw authority. On a delegated account only the portion above the delegated stake plus the reserve is withdrawable; on a deactivated one, anything above the reserve.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Vote accounts:&lt;/strong&gt; the vote program's &lt;code&gt;Withdraw&lt;/code&gt;, signed by the authorized withdrawer, keeping the rent-exempt minimum &lt;strong&gt;plus pending delegator rewards&lt;/strong&gt; — the delegators' accrued share is in the balance but is not the operator's to take. Once Alpenglow activates — the gate had not activated on mainnet as of 17 September 2026 — the account also has to keep &lt;a href="https://xroot.dev/blog/alpenglow-validator-admission-2000-seats" rel="noopener noreferrer"&gt;one epoch's admission ticket&lt;/a&gt;: 1.2 SOL at today's 300 ms slots, 1.0 SOL from epoch 1037, when slots go to 250 ms.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Token accounts:&lt;/strong&gt; &lt;code&gt;WithdrawExcessLamports&lt;/code&gt;, signed by the account's owner, an instruction both token programs carry precisely for this case. The account stays open and usable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing above closes anything, and nothing requires a third party to hold a key. The live tool on the app builds the batch for the accounts a connected wallet controls, and the wallet signs it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Switch That Can Put the Price Back Up
&lt;/h2&gt;

&lt;p&gt;The ladder has a reverse gear. A feature named &lt;code&gt;set_lamports_per_byte_to_6960&lt;/code&gt; restores the original price. It had not activated on mainnet as of 17 September 2026, and the validator's ordering rule gives it priority: if a rollback and a cut activate in the same epoch, &lt;strong&gt;the rollback wins&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The ordering rule for the cuts themselves is also worth knowing: if several cut gates activate in one epoch, the &lt;strong&gt;lowest&lt;/strong&gt; price wins; if they activate out of order, the &lt;strong&gt;most recently activated&lt;/strong&gt; price wins. The ladder is designed to descend, but the code allows for the messier cases.&lt;/p&gt;

&lt;p&gt;For anyone timing account creation to a cheaper step, the rollback is the risk. A batch deferred to "after the next cut" can land after a rollback instead. Watch both directions.&lt;/p&gt;




&lt;h2&gt;
  
  
  The IDs Changed Recently
&lt;/h2&gt;

&lt;p&gt;Feature gates are identified by public keys, and those keys are not stable until a feature activates. On &lt;strong&gt;11 September 2026&lt;/strong&gt; the SIMD-0438 rollback gate and the remaining SIMD-0437 cut gates were &lt;strong&gt;re-keyed&lt;/strong&gt; — assigned new feature IDs — in the validator source. Any dashboard, script or bookmark that tracked the old IDs is now watching accounts that will never activate.&lt;/p&gt;

&lt;p&gt;This is normal for unactivated features, and it is the reason the tracker on this site reads the feature names from the current validator build rather than from a list someone typed in months ago. If you track gates yourself, re-read the IDs from the release you are running, every release.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rent Surplus: Questions People Actually Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I get rent back from a Solana account without closing it?
&lt;/h3&gt;

&lt;p&gt;Yes, for account types whose program allows withdrawing lamports above the rent-exempt minimum: nonce, stake and vote accounts, and token accounts via WithdrawExcessLamports. The account stays open.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much rent surplus does a Solana account hold after the cut?
&lt;/h3&gt;

&lt;p&gt;(128 + data length) × (old price − new price) lamports. At the 5,080 per byte live since 11 September 2026, against the original 6,960, a token account holds about 0.00055 SOL of surplus; at the final step, about 0.0018 SOL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can the Solana rent cut be reversed?
&lt;/h3&gt;

&lt;p&gt;Yes. A rollback gate — not active on mainnet as of 17 September 2026 — restores 6,960 lamports per byte and overrides any cut that activates in the same epoch. Deferring account creation to a cheaper step carries that risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did the SIMD-0437 feature IDs change?
&lt;/h3&gt;

&lt;p&gt;Unactivated feature IDs are not stable. The remaining cut gates and the rollback gate were re-keyed on 11 September 2026; anything tracking the old IDs is watching dead accounts.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to Do, in Order
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  List the nonce, stake, vote and token accounts your keys control, with their creation-era balances.&lt;/li&gt;
&lt;li&gt;  Withdraw the surplus on the ones you keep, with the instruction for that type, leaving the current minimum and, for vote accounts, the delegators' share.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://xroot.dev/blog/claim-sol" rel="noopener noreferrer"&gt;Close the ones you do not need at all&lt;/a&gt;; closing returns the full original deposit, which is the larger number.&lt;/li&gt;
&lt;li&gt;  Then wait for the next step and do it again. Three steps remain, and each one makes every account you funded at the old price a little more over-funded than it was.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;— Without Closing a Single Account —&lt;/p&gt;

&lt;h3&gt;
  
  
  Take back the surplus and keep the account.
&lt;/h3&gt;

&lt;p&gt;The rent-refund tool reads the accounts a connected wallet controls, computes the surplus per type against the live byte price, and builds the withdrawal batch for your wallet to sign. Nothing is closed and no key leaves your side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.xroot.dev/solana/rent-cut-refund?ref=blog" rel="noopener noreferrer"&gt;Take Back the Rent Surplus ↗&lt;/a&gt;&lt;a href="https://app.xroot.dev/upgrades?ref=blog" rel="noopener noreferrer"&gt;Check which step is live&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While you are auditing stake accounts, the &lt;a href="https://xroot.dev/blog/solana-minimum-stake-delegation-1-sol" rel="noopener noreferrer"&gt;minimum delegation has been 1 SOL since 18 June 2026&lt;/a&gt; — the same accounts. A sub-1-SOL delegation still earns, but it can no longer be split or moved, only merged, deactivated or withdrawn.&lt;/p&gt;

&lt;p&gt;Rules and ordering read from the Agave validator source at commit &lt;code&gt;beee69b958&lt;/code&gt;: &lt;code&gt;runtime/src/bank.rs&lt;/code&gt;, &lt;code&gt;feature-set/src/lib.rs&lt;/code&gt; and the rent collector. The figures assume the 5,080 lamports-per-byte rate live on mainnet on 17 September 2026 — re-check the live rate and the live step before acting on a number here.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>rent</category>
      <category>simd0437</category>
      <category>walletrecovery</category>
    </item>
  </channel>
</rss>
