<?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: Vincent Jande</title>
    <description>The latest articles on DEV Community by Vincent Jande (@janvinsha).</description>
    <link>https://dev.to/janvinsha</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%2F740337%2Ff45216f6-e2cb-4b9d-a4d3-555f74ae1357.JPG</url>
      <title>DEV Community: Vincent Jande</title>
      <link>https://dev.to/janvinsha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/janvinsha"/>
    <language>en</language>
    <item>
      <title>Understanding Program Derived Addresses: The Solana Address That Has No Private Key</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Fri, 19 Jun 2026 12:23:35 +0000</pubDate>
      <link>https://dev.to/100daysofsolana/understanding-program-derived-addresses-the-solana-address-that-has-no-private-key-1mcg</link>
      <guid>https://dev.to/100daysofsolana/understanding-program-derived-addresses-the-solana-address-that-has-no-private-key-1mcg</guid>
      <description>&lt;p&gt;Every Solana program eventually hits the same question: where do I put my data, and how do I find it again later?&lt;/p&gt;

&lt;p&gt;Programs are stateless, so a program's data lives in separate accounts, each at an address. The moment you store something, you owe an answer to a problem databases tend to hide from you: what address does this live at, and how does the program find it again tomorrow? Program Derived Addresses are Solana's answer. The name scares people off, but the idea is mostly "an address you compute instead of remember, that only your program can control."&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem, in code
&lt;/h2&gt;

&lt;p&gt;Say each user gets a counter account. The normal way to make an account is to generate a fresh keypair and store data at its public key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Keypair&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@solana/web3.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Keypair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// counter.publicKey is something random, e.g. 7Hx4...9fT&lt;/span&gt;
&lt;span class="c1"&gt;// create the account at that address, write count = 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works. But the address is random, so nothing connects &lt;em&gt;this user&lt;/em&gt; to &lt;em&gt;that address&lt;/em&gt;. Tomorrow, when the user comes back to increment, how does your program find their counter? You're forced to keep a lookup table somewhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// the mapping you now have to store and never lose&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;9fYL...user1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;7Hx4...9fT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B2k9...user2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Qz1p...4dR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// ...times ten thousand users&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lose that table, lose the data, even though the accounts are right there on chain. You're storing files in a warehouse and writing the shelf number on a sticky note.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: compute the address from what you already know
&lt;/h2&gt;

&lt;p&gt;What if the address were a &lt;em&gt;function&lt;/em&gt; of the user instead of random? Give a function the word &lt;code&gt;"counter"&lt;/code&gt; and the user's public key, and it hands back a fixed address. Same inputs, same address, every time. No table.&lt;/p&gt;

&lt;p&gt;That's a PDA. &lt;strong&gt;PDAs are 32-byte addresses derived deterministically from a program ID and a set of seeds.&lt;/strong&gt; The seeds are the meaningful inputs you pick (here, &lt;code&gt;"counter"&lt;/code&gt; + the user's key). With &lt;code&gt;@solana/web3.js&lt;/code&gt;, the library Anchor's client uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PublicKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@solana/web3.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;counterPda&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bump&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findProgramAddressSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;      &lt;span class="c1"&gt;// a label&lt;/span&gt;
    &lt;span class="nx"&gt;userPublicKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBuffer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;    &lt;span class="c1"&gt;// the user's pubkey&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;MY_PROGRAM_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// counterPda is the SAME every time for this user. No mapping needed.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mapping table is gone: any time you need a user's counter, you re-derive it, and the address itself encodes who it belongs to. With Anchor you'll often skip the explicit call entirely and let the client derive PDAs from the IDL, but under the hood this is what runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The twist: it has no private key
&lt;/h2&gt;

&lt;p&gt;Normal addresses are public keys sitting on the Ed25519 elliptic curve, and every point on that curve has a matching private key. That private key is what signs transactions. But we just &lt;em&gt;hashed&lt;/em&gt; a counter address into existence without making a keypair, so who holds its private key?&lt;/p&gt;

&lt;p&gt;If the hash happened to land on the curve, some stranger might, which would let outsiders sign for your program's accounts. So Solana guarantees a PDA sits &lt;strong&gt;off the curve&lt;/strong&gt;, meaning no private key exists for it. That is the title: an address with no private key. It is the whole point, because it means only the program that derived it can control it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bump, in one example
&lt;/h2&gt;

&lt;p&gt;A given set of seeds plus the program ID produces a valid off-curve address only about half the time, so the derivation includes one more input: a single byte called the &lt;strong&gt;bump&lt;/strong&gt;. The search starts at 255 and counts down, hashing the seeds, the program ID, and the current bump together on each attempt until the result lands off the curve:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash(seeds + program_id + 255) -&amp;gt; on curve?  try 254
hash(seeds + program_id + 254) -&amp;gt; on curve?  try 253
hash(seeds + program_id + 253) -&amp;gt; off curve! use this.  bump = 253
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bump is part of the hash from the very first attempt at 255, not something added only after a bump-less hash fails. The first value that lands off-curve, the highest one that works, is the &lt;strong&gt;canonical bump&lt;/strong&gt;. &lt;code&gt;findProgramAddressSync&lt;/code&gt; returns it as the second value, the &lt;code&gt;bump&lt;/code&gt; above. You'll want to use the canonical bump rather than any other valid one, because the same seeds can produce &lt;em&gt;different&lt;/em&gt; valid addresses under different bumps, and accepting any of them would let an attacker slip a counterfeit account past your checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Anchor: derivation becomes a constraint
&lt;/h2&gt;

&lt;p&gt;On the program side, Anchor does the derivation and the check for you. Creating the counter (storing the bump for later):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Accounts)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Initialize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[account(&lt;/span&gt;
        &lt;span class="nd"&gt;init,&lt;/span&gt;
        &lt;span class="nd"&gt;payer&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;authority,&lt;/span&gt;
        &lt;span class="nd"&gt;space&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;Counter::INIT_SPACE,&lt;/span&gt;
        &lt;span class="nd"&gt;seeds&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="s"&gt;b"counter"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;authority&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;key()&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;as_ref()]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;bump&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                  &lt;span class="c1"&gt;// Anchor finds the canonical bump&lt;/span&gt;
    &lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;#[account(mut)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Signer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;system_program&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then later, validating it on every other instruction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Accounts)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Increment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[account(&lt;/span&gt;
        &lt;span class="nd"&gt;mut,&lt;/span&gt;
        &lt;span class="nd"&gt;seeds&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="s"&gt;b"counter"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;authority&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;key()&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;as_ref()]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;bump&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="py"&gt;.bump&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                   &lt;span class="c1"&gt;// reuse the stored bump&lt;/span&gt;
    &lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Signer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the &lt;code&gt;seeds&lt;/code&gt; line as a rule: &lt;em&gt;this account's address must derive from &lt;code&gt;"counter"&lt;/code&gt; and this authority's key.&lt;/em&gt; When the instruction runs, Anchor re-derives the address and checks that the passed-in account matches. Pass a different account and it's rejected before your code runs. The address is the proof, so there's no mapping left to tamper with. (Store the bump in your &lt;code&gt;Counter&lt;/code&gt; struct at init: &lt;code&gt;pub bump: u8&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;The difference between the two structs is the whole lifecycle: &lt;code&gt;init&lt;/code&gt; &lt;em&gt;creates&lt;/em&gt; the account at the derived address the first time and lets Anchor search for the canonical bump, while the plain &lt;code&gt;seeds&lt;/code&gt; + &lt;code&gt;bump = counter.bump&lt;/code&gt; form &lt;em&gt;validates&lt;/em&gt; an account that already exists, reusing the stored bump so it doesn't pay to re-search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four things that trip people up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Seed mismatch between client and program.&lt;/strong&gt; The seeds, their order, and their byte encoding need to match on both sides. &lt;code&gt;Buffer.from("counter")&lt;/code&gt; in the client has to line up with &lt;code&gt;b"counter"&lt;/code&gt; in the program, in the same position. One reordered or mistyped seed derives a different address, and the constraint rejects it. A lot of "my PDA doesn't match" bugs come down to this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not storing the bump.&lt;/strong&gt; If you don't save the canonical bump at init, every later instruction has to re-derive it by searching, which burns compute for no reason. Store it once in the account and reuse it with &lt;code&gt;bump = counter.bump&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treating the rejection as a bug.&lt;/strong&gt; When you pass the wrong account and the &lt;code&gt;seeds&lt;/code&gt; constraint throws, that's the security model working, not a failure. The point is that only the correctly derived address gets accepted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deriving without the canonical bump.&lt;/strong&gt; Other bump values can produce valid but &lt;em&gt;different&lt;/em&gt; addresses from the same seeds. Sticking with the canonical one, which is what Anchor's bare &lt;code&gt;bump&lt;/code&gt; and &lt;code&gt;findProgramAddressSync&lt;/code&gt; give you by default, keeps client and program in agreement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The payoff: a program that signs for itself
&lt;/h2&gt;

&lt;p&gt;No private key means no human can sign for a PDA, so how does a program move tokens out of an escrow it owns? The runtime gives the owning program a special power: the program whose ID derived the PDA can sign for it, through &lt;code&gt;invoke_signed&lt;/code&gt; during a cross-program invocation. The program's code becomes the authority, with no key anywhere.&lt;/p&gt;

&lt;p&gt;That's the foundation under most escrows, vaults, and lending pools on Solana: a program holding assets no human can drain, releasing them only by its own logic. We'll go deep on &lt;code&gt;invoke_signed&lt;/code&gt; and CPIs in the next post. For now, hold the shape: the missing private key isn't a weakness, it's what lets a program act as a trustless custodian.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Stateless programs store data in accounts at addresses; remembering random addresses doesn't scale.&lt;/li&gt;
&lt;li&gt;A PDA derives the address from seeds + program ID, so you recompute it instead of storing it.&lt;/li&gt;
&lt;li&gt;It's forced off the Ed25519 curve, so no private key exists and no outsider can sign for it.&lt;/li&gt;
&lt;li&gt;The canonical bump (counting down from 255) is the reproducible address you'll normally use.&lt;/li&gt;
&lt;li&gt;In Anchor, &lt;code&gt;seeds&lt;/code&gt; + &lt;code&gt;bump&lt;/code&gt; constraints derive and validate the account for you.&lt;/li&gt;
&lt;li&gt;The deriving program can sign for its own PDA (&lt;code&gt;invoke_signed&lt;/code&gt;), which is what powers escrows and vaults.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Going further
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://solana.com/docs/core/pda" rel="noopener noreferrer"&gt;Solana PDA docs&lt;/a&gt; cover derivation, the canonical bump, and the off-curve guarantee, with runnable examples on the &lt;a href="https://solana.com/docs/core/pda/pda-derivation" rel="noopener noreferrer"&gt;derivation page&lt;/a&gt; (the "Legacy" tab is the &lt;code&gt;@solana/web3.js&lt;/code&gt; version Anchor's client uses). The &lt;a href="https://www.anchor-lang.com/docs/basics/pda" rel="noopener noreferrer"&gt;Anchor PDA guide&lt;/a&gt; walks through the &lt;code&gt;seeds&lt;/code&gt; and &lt;code&gt;bump&lt;/code&gt; constraints you'll actually write, and the full &lt;a href="https://www.anchor-lang.com/docs/references/account-constraints" rel="noopener noreferrer"&gt;account constraints reference&lt;/a&gt; lists every constraint in one place.&lt;/p&gt;

&lt;p&gt;If you're doing 100 Days of Solana, the next arc puts all of this to work, and the challenges should now read like something you already understand. Not joined yet? It's not too late: &lt;a href="https://mlh.link/solana-100" rel="noopener noreferrer"&gt;mlh.link/solana-100&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Rust You Actually Need to Write Your First Anchor Program</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Sat, 13 Jun 2026 12:25:48 +0000</pubDate>
      <link>https://dev.to/100daysofsolana/the-rust-you-actually-need-to-write-your-first-anchor-program-4klc</link>
      <guid>https://dev.to/100daysofsolana/the-rust-you-actually-need-to-write-your-first-anchor-program-4klc</guid>
      <description>&lt;p&gt;If you have made it this far in 100 Days of Solana, you have been working in JavaScript and on the command line. You have been calling RPC methods, building instructions, signing transactions, and reading and writing account data in JavaScript, and most recently minting and sending tokens and NFTs from the CLI. Either way, you have been driving Solana with tools that let you assign a value and move on with your life. Soon the ground shifts. You are going to open a file called &lt;code&gt;lib.rs&lt;/code&gt;, and it is going to be Rust, and for a day or two it is going to feel like you forgot how to program.&lt;/p&gt;

&lt;p&gt;That feeling is normal, it is temporary, and it is not a sign you are in the wrong place. Here is the thing nobody says out loud: you do not need to learn all of Rust to write Solana programs. Rust is a big language with a steep reputation, but the slice of it that shows up in an Anchor program is small and repetitive. You will see the same handful of patterns on almost every line. Learn those patterns and the wall turns back into a floor.&lt;/p&gt;

&lt;p&gt;This post is that handful. Not a Rust course, just the parts you need to read your first Anchor program and understand what every line is doing. Next week we start Arc 9, the Anchor introduction, where this all becomes real. This week is about making the language stop being scary before you get there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it feels like a wall
&lt;/h2&gt;

&lt;p&gt;JavaScript is dynamically typed and garbage collected. You write &lt;code&gt;const x = 5&lt;/code&gt;, you never tell anyone it is a number, and when you are done with it the runtime quietly cleans up. The language trusts you and sorts out the consequences at runtime, which is why a typo surfaces as &lt;code&gt;undefined is not a function&lt;/code&gt; three minutes into a demo.&lt;/p&gt;

&lt;p&gt;Rust is the opposite philosophy. It is compiled and statically typed, so every value has a type the compiler knows about before the program ever runs, and it has no garbage collector, so it tracks who is responsible for every piece of memory through a system called ownership. The trade is blunt: Rust makes you front-load the thinking. The compiler refuses to build until the types line up and the ownership rules are satisfied. That is why the first day feels slow. You are paying upfront for something JavaScript billed you for later, usually in production.&lt;/p&gt;

&lt;p&gt;The reassuring part, and this is real, is that the Rust compiler is the most helpful error reporter you have ever worked with. A JavaScript bug explodes at runtime with a vague message and no map. A Rust bug stops at compile time with an error that names the file, the line, the types involved, and very often the exact fix to type. You will spend the Anchor arc reading compiler errors. Get good at reading them slowly instead of panicking at the red text, because nine times out of ten the answer is sitting right there in the message.&lt;/p&gt;

&lt;h2&gt;
  
  
  The anatomy of the file you are about to meet
&lt;/h2&gt;

&lt;p&gt;Before the individual pieces, here is the shape of a minimal Anchor program, taken straight from the &lt;a href="https://www.anchor-lang.com/docs/basics/program-structure" rel="noopener noreferrer"&gt;Anchor program structure docs&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anchor_lang&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;declare_id!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"11111111111111111111111111111111"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;#[program]&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;hello_anchor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Initialize&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.accounts.new_account.data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nd"&gt;msg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Changed data to: {}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Accounts)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Initialize&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[account(init,&lt;/span&gt; &lt;span class="nd"&gt;payer&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;signer,&lt;/span&gt; &lt;span class="nd"&gt;space&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;new_account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NewAccount&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;#[account(mut)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Signer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;system_program&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[account]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;NewAccount&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every Anchor program you write next week is a variation on those four blocks. The rest of this post walks through the Rust you need to read them without flinching.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;code&gt;use&lt;/code&gt; and the import line
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anchor_lang&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the Rust version of an import. &lt;code&gt;use&lt;/code&gt; brings names into scope so you do not have to write the full path every time, and the &lt;code&gt;*&lt;/code&gt; is a glob that pulls in everything from Anchor's &lt;code&gt;prelude&lt;/code&gt;, a curated bundle of the types and macros nearly every program needs. It is the same instinct as importing from a package in JavaScript, just with a &lt;code&gt;::&lt;/code&gt; path separator instead of a dot and slashes. When you later see errors about a type "not found in this scope," a missing &lt;code&gt;use&lt;/code&gt; line is the usual cause. You can read more in the &lt;a href="https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html" rel="noopener noreferrer"&gt;Rust book chapter on packages and modules&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Macros: the lines with &lt;code&gt;!&lt;/code&gt; and &lt;code&gt;#[...]&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is the single biggest "what am I looking at" moment for a JavaScript developer, so it gets the most space.&lt;/p&gt;

&lt;p&gt;Rust has macros, which are code that writes code at compile time. They are not functions. You can spot them two ways. A &lt;code&gt;!&lt;/code&gt; after a name, like &lt;code&gt;declare_id!(...)&lt;/code&gt;, &lt;code&gt;msg!(...)&lt;/code&gt;, or &lt;code&gt;require!(...)&lt;/code&gt;, means a macro call. And the bracketed attributes sitting above things, like &lt;code&gt;#[program]&lt;/code&gt;, &lt;code&gt;#[derive(Accounts)]&lt;/code&gt;, and &lt;code&gt;#[account]&lt;/code&gt;, are also macros, the attribute kind, that transform the item directly below them.&lt;/p&gt;

&lt;p&gt;Why this matters: Anchor is mostly macros. The whole point of the framework is that those attributes expand, at compile time, into the hundreds of lines of account-validation and serialization boilerplate that a raw Solana program makes you write by hand. The &lt;a href="https://www.anchor-lang.com/docs/basics/program-structure" rel="noopener noreferrer"&gt;Anchor docs&lt;/a&gt; describe the four you will see constantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;declare_id!&lt;/code&gt; sets your program's on-chain address.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#[program]&lt;/code&gt; marks the module that holds your instruction handlers. Each public function inside it becomes a callable instruction.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#[derive(Accounts)]&lt;/code&gt; goes on a struct to declare the list of accounts an instruction needs, and generates the validation for them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#[account]&lt;/code&gt; goes on a struct to mark it as a custom account type your program stores data in. Among other things it stamps an 8-byte discriminator on the account so the program can later prove the account is really one of its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You do not need to know how to write a macro. You need to recognize that when you see &lt;code&gt;#[derive(Accounts)]&lt;/code&gt;, an enormous amount of code you did not write is being generated for you, and that this is the framework doing its job. Treat the attributes as configuration you are declaring, not logic you are reading. The &lt;a href="https://doc.rust-lang.org/book/ch20-05-macros.html" rel="noopener noreferrer"&gt;Rust book's macro chapter&lt;/a&gt; is there if you get curious, but it is genuinely optional for the Anchor arc.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Structs: your data shapes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[account]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;NewAccount&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;struct&lt;/code&gt; is just a named bundle of fields, the same idea as a plain JavaScript object with a fixed shape, except the shape is declared and the compiler enforces it. &lt;code&gt;NewAccount&lt;/code&gt; has one field, &lt;code&gt;data&lt;/code&gt;, of type &lt;code&gt;u64&lt;/code&gt;, an unsigned 64-bit integer. You will define a struct for every kind of account your program stores, and another struct for every instruction's account list (those are the &lt;code&gt;#[derive(Accounts)]&lt;/code&gt; ones). When you read an Anchor program, structs are where you learn what data exists and what each instruction touches.&lt;/p&gt;

&lt;p&gt;A note on number types, because JavaScript hides this from you. JavaScript has one &lt;code&gt;number&lt;/code&gt;. Rust makes you pick: &lt;code&gt;u64&lt;/code&gt; is an unsigned (non-negative) 64-bit integer, &lt;code&gt;i64&lt;/code&gt; is signed, &lt;code&gt;u8&lt;/code&gt; is a byte, and so on. On Solana, &lt;code&gt;u64&lt;/code&gt; is everywhere because token amounts and counts are 64-bit. Picking the type is part of declaring your data, and it is why a counter's field is &lt;code&gt;count: u64&lt;/code&gt; and not just "a number."&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;code&gt;pub&lt;/code&gt;: who can see this
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pub&lt;/code&gt; means public. By default everything in Rust is private to its module, and &lt;code&gt;pub&lt;/code&gt; opts an item into being visible outside it. In Anchor you will see &lt;code&gt;pub fn&lt;/code&gt; on instruction handlers (the framework needs to call them from outside the module) and &lt;code&gt;pub&lt;/code&gt; on struct fields you want readable. It is access control at the language level, closer to &lt;code&gt;export&lt;/code&gt; in JavaScript modules than to anything in a plain object.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Functions and the return type
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Initialize&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fn&lt;/code&gt; declares a function. The parameters list their types after a colon, &lt;code&gt;data: u64&lt;/code&gt;, the same "name then type" order you have already seen in the struct. The part that is new is &lt;code&gt;-&amp;gt; Result&amp;lt;()&amp;gt;&lt;/code&gt;, the return type, which leads straight into the most important Rust concept for the week ahead.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. &lt;code&gt;Result&lt;/code&gt;, &lt;code&gt;Ok&lt;/code&gt;, and the &lt;code&gt;?&lt;/code&gt; operator: error handling without try/catch
&lt;/h2&gt;

&lt;p&gt;JavaScript handles errors by throwing and catching. Something fails, it throws, and somewhere up the stack a &lt;code&gt;try/catch&lt;/code&gt; maybe deals with it, or maybe it crashes. Nothing in the type system forces you to handle it.&lt;/p&gt;

&lt;p&gt;Rust has no exceptions. Instead, a function that can fail returns a &lt;code&gt;Result&lt;/code&gt;, a type that is either &lt;code&gt;Ok(value)&lt;/code&gt; for success or &lt;code&gt;Err(error)&lt;/code&gt; for failure. Every Anchor instruction handler returns &lt;code&gt;Result&amp;lt;()&amp;gt;&lt;/code&gt;, which reads as "this either succeeds with nothing meaningful to return, the empty &lt;code&gt;()&lt;/code&gt;, or it fails with an error." That is why every successful handler ends with &lt;code&gt;Ok(())&lt;/code&gt;: you are explicitly returning the success case. The &lt;a href="https://www.anchor-lang.com/docs/basics/program-structure" rel="noopener noreferrer"&gt;Anchor docs&lt;/a&gt; note that all Anchor instruction handlers return this &lt;code&gt;Result&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;The companion to &lt;code&gt;Result&lt;/code&gt; is the &lt;code&gt;?&lt;/code&gt; operator, and it is worth learning early because it is everywhere. When you call something that returns a &lt;code&gt;Result&lt;/code&gt; and write a &lt;code&gt;?&lt;/code&gt; after it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;something_that_can_fail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it means "if this is &lt;code&gt;Ok&lt;/code&gt;, unwrap the value and keep going; if it is &lt;code&gt;Err&lt;/code&gt;, stop this function right now and return that error to the caller." It is the same job a &lt;code&gt;try/catch&lt;/code&gt; does, compressed into one character, and it is how Anchor programs bubble failures up to the runtime cleanly. When you see &lt;code&gt;?&lt;/code&gt;, read it as "this line might bail out early, and that is intentional."&lt;/p&gt;

&lt;p&gt;You will also meet &lt;code&gt;Option&lt;/code&gt;, the cousin of &lt;code&gt;Result&lt;/code&gt;: it is &lt;code&gt;Some(value)&lt;/code&gt; or &lt;code&gt;None&lt;/code&gt;, and it is how Rust represents "this might be absent" instead of JavaScript's &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;. The reason Rust almost never has null-pointer surprises is that absence is a type you are forced to handle, not a landmine.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. References and &lt;code&gt;&amp;amp;mut&lt;/code&gt;: the ownership stuff
&lt;/h2&gt;

&lt;p&gt;Here is the concept with no JavaScript equivalent, and the one that produces the most head-scratching. Rust tracks ownership of data. Every value has one owner, and when you want to let other code use a value without handing over ownership, you lend it out with a reference, written &lt;code&gt;&amp;amp;&lt;/code&gt;. A plain &lt;code&gt;&amp;amp;&lt;/code&gt; is a read-only borrow. &lt;code&gt;&amp;amp;mut&lt;/code&gt; is a mutable borrow, meaning "I am lending you this and you are allowed to change it."&lt;/p&gt;

&lt;p&gt;You will see this constantly in handlers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.accounts.counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="py"&gt;.count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read &lt;code&gt;&amp;amp;mut ctx.accounts.counter&lt;/code&gt; as "get a mutable borrow of the counter account so I can write to it." Without &lt;code&gt;&amp;amp;mut&lt;/code&gt;, you would have a read-only view and the compiler would reject the assignment. The rule the compiler enforces, and the source of most early borrow-checker errors, is that you can have many readers or one writer, but not both at once. That sounds restrictive until you realize it is the rule that makes whole categories of bugs impossible.&lt;/p&gt;

&lt;p&gt;For the Anchor arc you do not need the deep theory. You need to recognize that &lt;code&gt;&amp;amp;&lt;/code&gt; means "borrowed, look but do not take," &lt;code&gt;&amp;amp;mut&lt;/code&gt; means "borrowed, allowed to change," and that when the compiler complains about borrowing it is protecting you from two pieces of code stepping on the same data. When you genuinely want to understand it, the &lt;a href="https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html" rel="noopener noreferrer"&gt;ownership chapter of the Rust book&lt;/a&gt; is the clearest explanation written, and the &lt;code&gt;Pubkey&lt;/code&gt; types being small and &lt;code&gt;Copy&lt;/code&gt; (cheap to duplicate, so you often pass them by value) is a footnote you will appreciate later.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Custom errors with enums
&lt;/h2&gt;

&lt;p&gt;When your program needs to reject something with a meaningful reason, you define an error type as an &lt;code&gt;enum&lt;/code&gt;, a type that is one of a fixed set of named variants:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[error_code]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;CounterError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[msg(&lt;/span&gt;&lt;span class="s"&gt;"The counter has reached its maximum value."&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Overflow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An &lt;code&gt;enum&lt;/code&gt; in Rust is more powerful than a JavaScript constant list, but for now read it as "a closed set of named options." The &lt;code&gt;#[error_code]&lt;/code&gt; attribute is Anchor wiring it into the program's error system, and the &lt;code&gt;#[msg(...)]&lt;/code&gt; lines are the human-readable strings that show up in logs when that error fires. You then raise one with the &lt;code&gt;require!&lt;/code&gt; macro or by returning &lt;code&gt;Err(...)&lt;/code&gt;. The &lt;a href="https://www.anchor-lang.com/docs/features/errors" rel="noopener noreferrer"&gt;Anchor errors guide&lt;/a&gt; covers the full pattern, and you will use it the moment your program needs to say no to bad input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;Read that minimal program one more time and notice you can now name every piece. &lt;code&gt;use&lt;/code&gt; pulls in Anchor. &lt;code&gt;declare_id!&lt;/code&gt; is a macro setting the address. &lt;code&gt;#[program]&lt;/code&gt; is an attribute macro marking the handler module. &lt;code&gt;initialize&lt;/code&gt; is a public function taking a &lt;code&gt;Context&lt;/code&gt; and some data, returning a &lt;code&gt;Result&lt;/code&gt;, ending in &lt;code&gt;Ok(())&lt;/code&gt;. The &lt;code&gt;#[derive(Accounts)]&lt;/code&gt; struct declares the accounts. The &lt;code&gt;#[account]&lt;/code&gt; struct declares the stored data shape, with a &lt;code&gt;u64&lt;/code&gt; field. None of it is mysterious anymore. It is the same eight ideas, arranged.&lt;/p&gt;

&lt;p&gt;That is the whole trick this week. You are not learning Rust the way a systems programmer learns Rust. You are learning to read a specific, repetitive dialect of it, and the vocabulary is small: imports, macros, structs, &lt;code&gt;pub&lt;/code&gt;, functions, &lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt;, references, and enums. Every program in the arc ahead is built from those.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to actually get through the week
&lt;/h2&gt;

&lt;p&gt;A few habits that will save you real time.&lt;/p&gt;

&lt;p&gt;Read the compiler errors top to bottom, slowly. Rust errors are long because they are thorough, not because they are angry. The first error is usually the real one; later errors are often just fallout. Fix the top one, recompile, repeat.&lt;/p&gt;

&lt;p&gt;Compile early and often. Do not write thirty lines and then build. Write a few, run &lt;code&gt;anchor build&lt;/code&gt;, see if it is happy, continue. Short feedback loops turn a scary language into a conversation.&lt;/p&gt;

&lt;p&gt;When the borrow checker fights you, stop and ask who owns this and who is borrowing it, rather than randomly adding and removing &lt;code&gt;&amp;amp;&lt;/code&gt; until it builds. The error message almost always tells you which rule you broke.&lt;/p&gt;

&lt;p&gt;And keep one tab open on the &lt;a href="https://www.anchor-lang.com/docs/basics/program-structure" rel="noopener noreferrer"&gt;Anchor program structure page&lt;/a&gt; and one on the &lt;a href="https://doc.rust-lang.org/book/" rel="noopener noreferrer"&gt;Rust book&lt;/a&gt;. You will not read either cover to cover. You will look up exactly the thing in front of you, which is the right way to learn a language you are using rather than studying.&lt;/p&gt;

&lt;p&gt;Next week the challenges move into Arc 9, the Anchor introduction, and these blog posts move with them. We leave the language topic behind here, not the program itself, and dig into Anchor properly: how accounts really work, what a Program Derived Address is and why it changes everything, and how the constraint system turns a struct into a security model. The daily challenges keep going as always; it is just this post's focus on the Rust language that wraps up today. For now, the goal is smaller and more important. Open &lt;code&gt;lib.rs&lt;/code&gt;, recognize the pieces, and let the compiler teach you. You already did the hard part by getting here.&lt;/p&gt;

&lt;p&gt;And if you have not joined the challenge yet, this is the moment. We are about to start writing real Solana programs, which is the part everything so far has been building toward. Jump in at &lt;a href="https://mlh.link/solana-100" rel="noopener noreferrer"&gt;mlh.link/solana-100&lt;/a&gt; and build it with us.&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>Fungible and Non-Fungible Tokens on Solana: Same System, Different Rules</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Fri, 29 May 2026 18:40:51 +0000</pubDate>
      <link>https://dev.to/100daysofsolana/fungible-and-non-fungible-tokens-on-solana-same-system-different-rules-3h3</link>
      <guid>https://dev.to/100daysofsolana/fungible-and-non-fungible-tokens-on-solana-same-system-different-rules-3h3</guid>
      <description>&lt;p&gt;If you have been following the 100 Days of Solana challenges, you have already worked with tokens. You created mints, set up token accounts, transferred SOL, and explored token extensions. But there is a distinction that comes up constantly in web3, and understanding it properly will change how you think about everything you build going forward.&lt;/p&gt;

&lt;p&gt;Fungible and non-fungible tokens. You have probably heard these terms before, especially NFTs. But what do they actually mean on Solana, and how does the same token system handle two very different concepts?&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes something fungible
&lt;/h2&gt;

&lt;p&gt;Fungible just means interchangeable. One unit is identical to another unit. If I have 10 USDC and you have 10 USDC, ours are exactly the same. It does not matter which specific USDC tokens I hold because they are all worth the same and behave the same way. We could swap them and nothing changes.&lt;/p&gt;

&lt;p&gt;This is how most things you are used to work. A dollar bill is fungible. A liter of petrol is fungible. One unit of SOL is the same as any other unit of SOL. When you built token transfers in the challenges, you were working with fungible tokens. You did not need to care about which specific tokens moved, just how many.&lt;/p&gt;

&lt;p&gt;Fungible tokens are used for currencies, stablecoins, utility tokens, governance tokens, loyalty points, in-game currencies, and anything where the quantity matters more than the individual unit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes something non-fungible
&lt;/h2&gt;

&lt;p&gt;Non-fungible means unique. Each token is different from every other token, even if they come from the same collection. If I have NFT #42 from a collection and you have NFT #87, those are not interchangeable. They might have different images, different properties, different rarity, or different utility.&lt;/p&gt;

&lt;p&gt;Think of it like event tickets. Two tickets to the same concert are not the same if one is front row and the other is in the back. They came from the same event, but each one is distinct.&lt;/p&gt;

&lt;p&gt;Non-fungible tokens are used for digital art, collectibles, membership passes, certifications, domain names, gaming items, real estate deeds, event tickets, and anything where the individual item matters more than the quantity.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Solana handles both with the same system
&lt;/h2&gt;

&lt;p&gt;This is where Solana does something interesting. On some blockchains, fungible and non-fungible tokens are completely separate systems with different standards and different smart contracts. On Solana, both run through the same Token Program (or the newer Token Extensions program, also called Token-2022).&lt;/p&gt;

&lt;p&gt;The difference comes down to two configuration settings: decimals and supply.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A fungible token has a mint initialized with multiple decimals (typically 6 or 9) and a supply far greater than one. You can mint millions of fractional units from the same mint, and they are all interchangeable.&lt;/li&gt;
&lt;li&gt;A non-fungible token is a mint initialized with exactly 0 decimals, where exactly one token is minted and the mint authority is then permanently revoked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That second part is worth being precise about, because there is no "maximum supply" field you set when you create a base SPL mint. A mint has a supply value that simply increments every time you mint into it. You create the mint with 0 decimals, mint exactly one token to a token account, and then set the mint authority to None. Revoking the authority is what locks the total supply at 1 forever, guaranteeing that no more units of this specific token can ever be printed.&lt;/p&gt;

&lt;p&gt;Same program, same mint account layout. The rules are enforced purely by how you configure the mint and what you do with the mint authority.&lt;/p&gt;

&lt;p&gt;One nuance: at this level you have created a non-fungible token. Wallets and marketplaces do not yet recognize it as an "NFT" in the way you would see it on a marketplace. That recognition comes from the metadata and standard layer, which is what we cover next.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The role of metadata
&lt;/h2&gt;

&lt;p&gt;If a non-fungible token is just a mint with a supply of one, how do you know what it actually represents? How do you attach an image, a name, or specific traits to it?&lt;/p&gt;

&lt;p&gt;This is where metadata comes in. On-chain, a token mint is just a state account holding configuration details and balances. The metadata gives it context.&lt;/p&gt;

&lt;p&gt;The long-standing approach is the Metaplex Token Metadata standard, which creates a separate metadata account cryptographically linked to the token mint via a Program Derived Address (PDA). This account holds the token's name, symbol, and a URI pointing to an off-chain JSON file containing the image and attributes. That JSON is typically stored on decentralized storage like Arweave or IPFS, though some projects use centralized hosting such as AWS S3.&lt;/p&gt;

&lt;p&gt;Token Metadata is still widely used and is not deprecated. Interestingly, a large share of assets minted through it today are actually fungible tokens, since it is also the common way to give a fungible mint a name, symbol, and icon.&lt;/p&gt;

&lt;p&gt;For new NFT projects specifically, the current recommended standard is &lt;strong&gt;Metaplex Core&lt;/strong&gt;. Core uses a single-account design, storing all of an asset's data in one account instead of the separate mint, metadata, and token accounts the older model required. That cuts minting cost dramatically (on the order of 80 percent cheaper than Token Metadata) and ships with built-in features like enforced royalties and a plugin system for custom behavior. If you are starting a new NFT collection today, Core is usually where you should look first.&lt;/p&gt;

&lt;p&gt;There is also the &lt;strong&gt;Token Extensions (Token-2022)&lt;/strong&gt; path. By enabling the MetadataPointer and TokenMetadata extensions, you can store the name, symbol, and URI directly inside the mint account itself. The pointer says where the metadata lives, and the metadata extension holds the actual fields. In practice this is used most often for fungible and utility tokens, letting a stablecoin or reward token carry a native icon and tracking data without a separate metadata account or any cross-program coordination at creation.&lt;/p&gt;

&lt;p&gt;So the honest map of the landscape is: Token Metadata (legacy, still common, heavily used for fungibles), Core (the modern recommendation for new NFTs), Token-2022 metadata extensions (great for fungible and utility tokens), and compressed NFTs for high-volume cases, which we will get to in a moment.&lt;/p&gt;

&lt;p&gt;For fungible tokens, metadata is simple. You usually just need a name, symbol, and maybe an icon. For non-fungible tokens, metadata can be extensive because each token is unique and needs its own description, image, and properties.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9kyia5kpp557f458zf5y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9kyia5kpp557f458zf5y.png" alt="A horizontal flow: Token Account (balance: 1) → Mint Account → Metadata, where Metadata branches into two stacked boxes labeled " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Token accounts work the same way
&lt;/h2&gt;

&lt;p&gt;Whether you are holding a fungible token or a non-fungible one, you need a token account for it. This is the same concept you learned in the challenges. Your wallet needs an Associated Token Account (ATA) for each mint you want to hold.&lt;/p&gt;

&lt;p&gt;For fungible tokens, your token account has a balance that can go up and down as you send and receive tokens. For non-fungible tokens, your token account has a balance of exactly one. You either have it or you do not.&lt;/p&gt;

&lt;p&gt;The mechanics are identical. Creating the account, paying rent, transferring tokens. The same code patterns you have been writing in the challenges apply to both. (Metaplex Core is the one exception worth noting, since its single-account model does not use a separate token account in the same way, but the fungible side and classic NFTs both follow the familiar ATA pattern.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5vo1woaf0xgovkuufuh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5vo1woaf0xgovkuufuh.png" alt="Digital asset spectrum, ranging from pure fungible tokens to unique non-fungible assets," width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Editions, collections, and scale
&lt;/h2&gt;

&lt;p&gt;Not every NFT is a complete one-of-one. Sometimes you want to create multiple copies of the same item but still have each one be individually trackable. Think limited edition prints. There are 500 of them, each one is numbered, but they all share the same artwork.&lt;/p&gt;

&lt;p&gt;In the Token Metadata standard, this is handled through editions. A master edition can produce a set number of prints. Each print is its own mint with its own token, but they are all linked back to the original master edition.&lt;/p&gt;

&lt;p&gt;Collections group related NFTs together. A collection is itself an NFT that acts as a parent. Individual NFTs reference the collection in their metadata, which is how marketplaces know that 10,000 different mints all belong to the same project.&lt;/p&gt;

&lt;p&gt;Here is an important practical point that trips people up. Editions and one-mint-per-item NFTs do not scale cheaply. Each one is a real account that carries rent. So if your goal is something like 1,000 identical-but-individually-owned event tickets, minting a thousand separate full NFTs gets expensive fast.&lt;/p&gt;

&lt;p&gt;For that high-volume case, the modern answer is &lt;strong&gt;compressed NFTs&lt;/strong&gt; (the Metaplex Bubblegum standard). Compressed NFTs store ownership data in a Merkle tree rather than in a full account per token, which makes it possible to mint thousands or even millions of individually owned, transferable assets at a tiny fraction of the cost. This is the dominant approach for large drops on Solana today, and it is exactly what you would reach for in the 1,000-ticket scenario.&lt;/p&gt;

&lt;p&gt;So the decision for "many of the same thing" is really: a handful of numbered prints can use editions, but anything at real scale should use compression.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdzerb3a04x0nn7dxl89s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdzerb3a04x0nn7dxl89s.png" alt="A three-column comparison (table or cards): Token Metadata vs Core vs Bubblegum (compressed). Rows for " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fungible tokens with NFT properties
&lt;/h2&gt;

&lt;p&gt;The Token Extensions program blurs the traditional line between fungible and non-fungible tokens in powerful ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Non-Transferable Tokens&lt;/strong&gt;: By initializing a fungible mint with the NonTransferable extension, you create assets that are locked to the recipient's wallet the moment they are minted. If a user earns 50 reputation points, those points are structurally fungible but behave like "soulbound" credentials because the runtime blocks any transfer instruction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mint-Linked Metadata&lt;/strong&gt;: Before Token Extensions, detailed metadata was largely reserved for NFTs via Metaplex. Now, you can inject rich metadata directly into a fungible utility token or stablecoin mint, allowing wallets to display custom icons and tracking data natively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transfer Hooks&lt;/strong&gt;: You can attach a custom program to a fungible token mint that executes additional logic every time a transfer occurs. A fungible token that checks an allowlist or verifies a KYC credential before allowing a transfer begins to behave like a restricted real-world security, changing its economic behavior entirely through code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The categories are not as rigid as they seem. Solana gives you the building blocks and you decide how to combine them.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use which
&lt;/h2&gt;

&lt;p&gt;If you are building something where every unit is the same and users care about quantity, use a fungible token. Currencies, points, credits, governance votes.&lt;/p&gt;

&lt;p&gt;If you are building something where each item is unique and users care about the specific item they hold, use a non-fungible token. Art, collectibles, certificates, tickets, identity documents. For a brand-new collection, start with Metaplex Core. For high-volume drops, reach for compressed NFTs.&lt;/p&gt;

&lt;p&gt;If you are building something in between, like a limited-edition with 100 copies or a membership tier with different levels, look at editions and collections, or explore how Token-2022 extensions can give you the behavior you need.&lt;/p&gt;

&lt;p&gt;The good news is that the skills you are building in these challenges apply to all of it. The mint, token account, and transfer patterns are the same regardless of whether you are working with fungible or non-fungible tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is coming next
&lt;/h2&gt;

&lt;p&gt;The upcoming challenges will take you deeper into how NFTs work on Solana, how to mint them, how metadata is structured, and how collections come together. Understanding the foundation covered here will make those challenges click faster.&lt;/p&gt;

&lt;p&gt;Keep building. See you in the Discord.&lt;/p&gt;

&lt;p&gt;100 Days of Solana is a free daily coding challenge: &lt;a href="https://mlh.link/solana-100" rel="noopener noreferrer"&gt;https://mlh.link/solana-100&lt;/a&gt;&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>Web3 Apps You Can Build With Token Extensions</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Fri, 22 May 2026 20:07:47 +0000</pubDate>
      <link>https://dev.to/100daysofsolana/web3-apps-you-can-build-with-token-extensions-me8</link>
      <guid>https://dev.to/100daysofsolana/web3-apps-you-can-build-with-token-extensions-me8</guid>
      <description>&lt;p&gt;In our previous articles, we covered &lt;a href="https://dev.to/100daysofsolana/how-web3-tokens-get-their-value-3bbk"&gt;how Web3 tokens get their value&lt;/a&gt; and broke down the new standards in &lt;a href="https://dev.to/100daysofsolana/what-is-token-2022-and-why-solana-built-it-53io"&gt;What is Token 2022 and why Solana built it&lt;/a&gt;. You understand authorities, token accounts, and the extensions available.&lt;/p&gt;

&lt;p&gt;Now the question is what you actually build.&lt;/p&gt;

&lt;p&gt;Token extensions are building blocks for real products. Each extension solves a specific problem. By leveraging Token 2022 via modern client libraries, you can build applications from frontend or backend scripts that would have required custom smart contracts before.&lt;/p&gt;

&lt;p&gt;Here are some app ideas, the extensions they use, and the tools to start building them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ugcjs97lcplom3rb7xp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ugcjs97lcplom3rb7xp.png" alt="A row of simple glowing tokens on the left flowing through thin light streams into a larger central platform with translucent floating cards arranged around it." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Creator Subscription Platform
&lt;/h2&gt;

&lt;p&gt;Subscribers hold a token that grants monthly access to exclusive content. The token cannot be resold or moved between wallets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extensions&lt;/strong&gt;: Non-transferable tokens prevent resale; metadata stores the creator name, tier, and subscription period.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;: Create one mint per creator per subscription period, one for "Creator X - January 2026," another for February. When a user subscribes, bundle a USDC payment with a non-transferable token mint into a single atomic transaction.&lt;/p&gt;

&lt;p&gt;Use one mint per period because Token-2022 metadata is mint-level, every holder of a given mint reads the same expiry. Gating access is then a direct read of the period from the mint's on-chain metadata against the current date.&lt;/p&gt;

&lt;p&gt;To reclaim or burn subscription tokens directly, add PermanentDelegate at mint creation. The extension itself can never be removed once the mint is initialized, though the delegate authority can be rotated or set to None via SetAuthority.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;: @solana/kit, @solana-program/token-2022, Next.js or React.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  2. Loyalty Rewards Program
&lt;/h2&gt;

&lt;p&gt;A business issues loyalty points as tokens. Customers earn points on purchases and redeem them for discounts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extensions&lt;/strong&gt;: Non-transferable tokens keep points tied to the customer; the business retains mint authority to issue new points; metadata displays the brand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;: Each business gets its own token mint. The backend mints points directly into the customer's token account on purchase events. Customers connect their wallet to a redemption portal to spend points.&lt;/p&gt;

&lt;p&gt;On-chain identity here is pseudonymous, not private, wallet balances and minting activity are visible to anyone. Non-transferability stops third parties from trading or seizing the points, but doesn't hide them from view.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;: @solana/kit, @solana-program/token-2022, Node.js, React, Solana Pay.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7qmoyorl0g3rsnjm4fl3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7qmoyorl0g3rsnjm4fl3.png" alt="A glowing storefront-shaped block with small luminous tokens streaming out toward a translucent wallet card" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Regulated Investment Token
&lt;/h2&gt;

&lt;p&gt;A real estate company tokenizes a property. Only verified investors can hold the token, and the company needs a way to freeze accounts and recover tokens if compliance requires it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extensions&lt;/strong&gt;: Default account state can be set to frozen so new holders start out locked until KYC clears. Freeze authority handles ongoing compliance actions, like freezing an account that falls out of good standing. A permanent delegate provides a recovery path for legal scenarios. Metadata stores property details and links to legal documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;: New investor token accounts start frozen and are thawed after the investor passes KYC. The freeze authority can re-freeze any account later if compliance requires it, and the permanent delegate handles court-ordered recovery if it ever comes to that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;: @solana/kit and @solana-program/token-2022 for the mint, freeze actions, and delegate operations, plus a KYC provider API for investor verification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fviovtbjzixdluf7jvfyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fviovtbjzixdluf7jvfyt.png" alt="A translucent building-shaped block split into glowing fragments, with a faint shield outline in front and a small padlock symbol floating beside it." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. In-Game Currency with Transaction Fees
&lt;/h2&gt;

&lt;p&gt;Players earn an in-game currency through gameplay and trade it with each other. The studio automatically collects a small fee on every user-to-user transfer to generate ongoing revenue from the game economy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extensions&lt;/strong&gt;: Transfer fees collect a percentage on every token movement; metadata handles branding like names, icons, and descriptions; mint authority is retained so the studio can inject new currency into the economy via gameplay achievements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;: Fees are configured at mint creation and collected automatically on token transfers with no custom program or market smart contract required. When players send tokens to each other, the configured fee is withheld directly inside the recipient's token account.&lt;/p&gt;

&lt;p&gt;Because fees accumulate quietly inside thousands of individual player accounts, the studio's withdraw-withheld authority can periodically collect these withheld amounts and pool them into a central treasury wallet, without touching player balances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt;: @solana/kit, @solana-program/token-2022, a game client SDK, and an administrative backend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7yc59n7a1qxo461hhtm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7yc59n7a1qxo461hhtm.png" alt="Two translucent player avatars facing each other with glowing tokens flowing between them, small droplets falling into a luminous chest below." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Patterns to Notice
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;@solana-program/token-2022 is often all you need&lt;/strong&gt;. For loyalty, subscriptions, in-game currencies, and yield-bearing wrappers, you can usually compose instructions against it from @solana/kit and skip Rust. Reach for Anchor when you need to build custom programs or manage complex state logic that standard extensions don't cover.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plan compatibility before mint creation&lt;/strong&gt;. Not every extension pairs with every other extension. Some combinations are blocked because their behaviors conflict (for example, anything that gates or modifies transfers tends to clash with non-transferability). Most extensions can't be added after mint creation, so check the compatibility matrix in the Token-2022 docs before committing to a design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"No Rust required" is not "no centralized authority required."&lt;/strong&gt; Permanent delegate, freeze authority, mint authority, and withdraw-withheld authority are centralized controls encoded in extension config. If any are live on your token, make sure to state them clearly in your project's docs or UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start thinking about what you want to build
&lt;/h2&gt;

&lt;p&gt;You have the fundamentals. The app ideas above are starting points, take one, modify it, make it your own.&lt;/p&gt;

&lt;p&gt;Keep building. See you on Discord.&lt;/p&gt;

&lt;p&gt;100 Days of Solana is a free daily coding challenge: &lt;a href="https://mlh.link/solana-100" rel="noopener noreferrer"&gt;https://mlh.link/solana-100&lt;/a&gt;&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>What Is Token 2022 and Why Solana Built It</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Fri, 15 May 2026 19:29:20 +0000</pubDate>
      <link>https://dev.to/100daysofsolana/what-is-token-2022-and-why-solana-built-it-53io</link>
      <guid>https://dev.to/100daysofsolana/what-is-token-2022-and-why-solana-built-it-53io</guid>
      <description>&lt;p&gt;Last week, we examined the economic theories that underpin the value of Web3 tokens. This week, we are shifting our focus to the engineering reality of how these assets actually function on the Solana blockchain. As you begin building with tokens in the upcoming challenges, the nuances of account ownership and program logic will become the foundation of your development workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Library Model: Why One Program Rules
&lt;/h2&gt;

&lt;p&gt;On many virtual machine blockchains, every token exists as its own independent smart contract that contains both the rules and the ledger. In that model, the ledger for a token is essentially a massive list stored inside a single contract. Solana utilizes a fundamentally different architecture by strictly separating logic from data, which is known as an account-based architecture.&lt;/p&gt;

&lt;p&gt;Instead of requiring developers to deploy new code for every individual asset, Solana provides the &lt;strong&gt;SPL Token Program&lt;/strong&gt;. This single, audited, and highly optimized program handles the logic for nearly every standard token on the network. When you create a new token on Solana, you are not deploying a smart contract. You are instead asking the Token Program to initialize a new Mint Account and designating that program as the owner. In this context, the owner refers specifically to the program that has the permission to modify the data within that account.&lt;/p&gt;

&lt;p&gt;This standardized approach ensures that every asset follows the same predictable execution paths. This consistency is a major security feature because it reduces the surface area for logic bugs and allows every wallet or exchange to interact with any token without needing to audit unique code. The original Token Program was designed with a rigid, fixed-size account layout that handled the basics like minting and transferring, but it lacked the flexibility to adapt to the complex requirements of modern decentralized finance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accounts: Your Blockchain Mailboxes
&lt;/h2&gt;

&lt;p&gt;To understand Solana development, you must internalize the concept that your wallet does not actually contain tokens. Instead, your wallet address acts as an authority over a specific Token Account. You can think of your wallet as a master key and the Token Account as a specialized mailbox located elsewhere on the ledger. If you wish to hold three different types of tokens, you must have three distinct Token Accounts.&lt;/p&gt;

&lt;p&gt;Allocating space on the blockchain ledger for these data accounts requires a deposit of SOL known as the &lt;strong&gt;Rent-Exempt Minimum&lt;/strong&gt;. This deposit ensures the network remains performant by preventing the accumulation of empty accounts. In modern applications, we typically use the Associated Token Account pattern. This is a deterministic way of finding a token account address using a user’s main wallet address, the token’s mint address, and the specific Token Program ID being used. Because the address is predictable, the sender can automatically initialize the mailbox for a user before sending them tokens, which solves the friction of manual account creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorities and Governance
&lt;/h2&gt;

&lt;p&gt;Every token minted on Solana is governed by specific authorities that define the lifecycle of the asset. The &lt;strong&gt;Mint Authority&lt;/strong&gt; is the address granted permission to generate new tokens, which directly controls the circulating supply. When a project claims its supply is hard-capped, it generally means they have renounced this authority by setting it to null. Once renounced, the supply is mathematically frozen and no further tokens can ever be created.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Freeze Authority&lt;/strong&gt; is a more powerful component that allows a specific wallet to lock an individual token account. A frozen account is completely immobilized and cannot receive, transfer, or burn tokens until it is explicitly thawed by the authority. While this level of control is often viewed with skepticism in purely decentralized communities, it is crucial for regulated assets, such as stablecoins, to comply with legal requirements or freeze assets involved in theft. For a developer, auditing these authorities is the first step in assessing the risk profile of any token.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Evolution: Token 2022
&lt;/h2&gt;

&lt;p&gt;As the Solana ecosystem matured, developers began hitting the ceiling of the original Token Program’s fixed layout. If you wanted to add a transfer fee or metadata to a token, there was simply no space left in the original account structure to store that information. This led to the creation of &lt;strong&gt;Token 2022&lt;/strong&gt;, which is also known as the &lt;strong&gt;Token Extensions Program&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Token 2022 is an upgraded version of the original functionality that utilizes a more flexible data structure. This allows the program to support an expandable list of features without breaking compatibility with the original instruction set.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transfer Fees&lt;/strong&gt;: This extension allows projects to implement protocol-level fees without custom token logic. A configurable fee can be withheld from transfers and later withdrawn by the designated authority, allowing projects to generate revenue directly from token activity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidential Transfers&lt;/strong&gt;: This extension utilizes Zero-Knowledge Proofs to encrypt balances and transfer amounts. The network can mathematically verify that a transaction is valid without ever revealing the specific numbers to the public ledger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transfer Hooks&lt;/strong&gt;: This is a powerful tool for developers because it allows a mint to require that every transfer call a secondary program. This enables logic such as mandatory identity checks or automated royalty enforcement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Metadata&lt;/strong&gt;: Developers can now store names and symbols directly within the mint account. This reduces the reliance on separate metadata systems for simpler use cases and reduces the overall complexity of your code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permanent Delegate&lt;/strong&gt;: This extension allows a specific authority to move or burn tokens from any account. While powerful, it is essential for institutional compliance and the recovery of assets in legal disputes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Matters for the Challenges Ahead
&lt;/h2&gt;

&lt;p&gt;As you progress through the coding challenges, you will be responsible for choosing when to use the legacy Token Program and when to leverage the advanced capabilities of Token 2022. Understanding the relationship between programs and accounts will save you hours of debugging when a transaction fails due to a missing account or an unauthorized signer. You are not just learning to code, you are learning to architect on a global and parallelized ledger. The flexibility of Token 2022 represents the next chapter of Solana’s growth by shifting tokens from simple balance entries into complex and programmable financial instruments.&lt;/p&gt;

&lt;p&gt;Keep building and pay close attention to the account constraints in your upcoming programs. The precision you apply today will be the security of the protocols you deploy tomorrow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;See you on Discord&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;100 Days of Solana&lt;/strong&gt; is a free daily coding challenge. If you have not joined yet, you can start your journey here: &lt;a href="https://mlh.link/solana-100" rel="noopener noreferrer"&gt;https://mlh.link/solana-100&lt;/a&gt;&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>learning</category>
      <category>web3</category>
      <category>solana</category>
    </item>
    <item>
      <title>How Web3 Tokens Get Their Value</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Thu, 07 May 2026 18:03:23 +0000</pubDate>
      <link>https://dev.to/100daysofsolana/how-web3-tokens-get-their-value-3bbk</link>
      <guid>https://dev.to/100daysofsolana/how-web3-tokens-get-their-value-3bbk</guid>
      <description>&lt;p&gt;Someone in the 100 Days of Solana community asked a question last week that needs to be addressed: "What gives SOL its value?"&lt;/p&gt;

&lt;p&gt;You have been using SOL in every challenge. You airdropped it, checked your balance, and you are about to start sending it in Arc 3. But where does the value actually come from? Is it just numbers on a screen?&lt;/p&gt;

&lt;p&gt;I understand why people think that. Let’s break it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Liquidity: Where price comes from&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The first thing to understand is that for a token to have purchasing power, there needs to be liquidity. This means there are people or pools willing to trade real assets, such as fiat or stablecoins, for that token. That liquidity is what allows a market price to exist.&lt;/p&gt;

&lt;p&gt;Think of it like converting currencies at an airport. You hand over dollars, and you get euros. The value isn't created in that moment; it is a transfer of value from one form to another. In Web3, liquidity is the bridge that connects digital assets to the broader economy.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Different tokens, different sources of value&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Not all tokens work the same way. Understanding the types helps you see where the value sits.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native Tokens: SOL is required to pay transaction fees, stake with validators, and interact with applications. As usage of the network grows, the demand for these specific functions can increase the demand for SOL.&lt;/li&gt;
&lt;li&gt;Stablecoins: These are often pegged to a currency like the US dollar. They maintain this peg through reserves and market mechanics. Issuers like Circle hold cash and bonds so you can redeem USDC for dollars.&lt;/li&gt;
&lt;li&gt;Utility Tokens: These provide access to specific services, such as in-game items or decentralized file hosting. The token has value because the service it unlocks is useful to someone.&lt;/li&gt;
&lt;li&gt;Governance Tokens: These provide voting power. Holding governance tokens for a protocol allows participation in decisions about fees, features, or treasury management.&lt;/li&gt;
&lt;li&gt;Meme Tokens: These often derive value from community and attention. While they may begin as jokes, they can build large social networks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Solana-Specific Engine&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Beyond general categories, Solana has unique technical mechanics that influence its economy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The Cost of State (Rent) On Solana, storage is not free. Every time you create an account or deploy a program, you must deposit a minimum amount of SOL to make that account Rent Exempt. This SOL is held in the account to keep it active. While it isn't permanently removed, it is temporarily locked, which can reduce circulating liquidity as the ecosystem grows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Burn Mechanism Solana has a built-in "fee burn" where 50% of every base transaction fee is permanently destroyed. However, Solana also has inflation (new SOL issued to validators to secure the network). The net effect on supply depends on how much network activity (burn) occurs versus the rate of new issuance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Efficiency via Proof of History (PoH) Solana’s design enables fast, low-cost transactions (settling in roughly 400ms). This can make certain applications, like high frequency DeFi or real time payments, more efficient. This efficiency increases the usefulness of the network, which in turn supports the value of its native token.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Liquidity pools: How tokens stay tradeable&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In Web3, we often use liquidity pools instead of traditional order books. A liquidity pool is a smart contract holding two tokens, such as SOL and USDC. Prices are set automatically using mathematical formulas rather than matching individual buyers and sellers like a traditional exchange.&lt;/p&gt;

&lt;p&gt;People who deposit tokens into these pools are called liquidity providers. They put in a balanced value of both tokens and earn a portion of the trading fees. This is how decentralized exchanges like Raydium or Orca function. When more people buy SOL from the pool, it becomes scarcer in that pool, and the price rises automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Is it real?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Value in Web3 comes from the same place all value comes from: utility and demand.&lt;/p&gt;

&lt;p&gt;SOL is useful because the network processes thousands of transactions per second for very low costs. USDC is useful because it allows for digital dollar movement globally. DeFi protocols are useful because they provide financial tools without traditional intermediaries.&lt;/p&gt;

&lt;p&gt;The infrastructure is different from traditional finance, but the principles are the same. Value frequently follows utility.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What this means for you&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You have been working with DevNet SOL, which has no monetary value. However, the mechanics are identical to Mainnet. The RPC calls, the wallet interactions, and the transaction flows are all the same.&lt;/p&gt;

&lt;p&gt;In Arc 3, you start sending transactions and moving "simulated value." Understanding how that value flows, even on a test network, makes you a better builder. You are practicing the exact same movements you will eventually perform on Mainnet. Whether you end up creating a payment system, a DeFi protocol, or something entirely new, this technical foundation is where it starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep building. See you on Discord.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;100 Days of Solana is a free daily coding challenge. If you have not joined yet, start here: &lt;a href="https://mlh.link/solana-100" rel="noopener noreferrer"&gt;https://mlh.link/solana-100&lt;/a&gt;&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>learning</category>
      <category>web3</category>
      <category>solana</category>
    </item>
    <item>
      <title>Why Web3 Exists and Why Solana Matters</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Tue, 28 Apr 2026 18:19:40 +0000</pubDate>
      <link>https://dev.to/100daysofsolana/why-web3-exists-and-why-solana-matters-296h</link>
      <guid>https://dev.to/100daysofsolana/why-web3-exists-and-why-solana-matters-296h</guid>
      <description>&lt;p&gt;You trust middlemen every single day. You probably don't even think about it.&lt;/p&gt;

&lt;p&gt;Your bank holds your money. Instagram holds your followers. Spotify holds your playlists. Google holds your emails. Every service you use, someone else is in control. They control access to your data and assets within their systems and policies.&lt;/p&gt;

&lt;p&gt;In our current digital landscape, our "ownership" is essentially a managed service. Whether it's a financial institution or a social media platform, your access depends on the stability and policies of the provider. Web3 is the movement to change this, to build an internet where you actually own your digital assets and data.&lt;/p&gt;

&lt;p&gt;To make this vision a reality, we need a foundation that doesn't rely on a central boss. This is precisely what blockchain was designed to provide.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what is a blockchain?
&lt;/h2&gt;

&lt;p&gt;Imagine a notebook that thousands of people have a copy of. Every time someone writes something in it, every copy is updated simultaneously, provided the network agrees the entry meets specific conditions. You can't rip out a page, change what was already written, or claim ownership over the whole thing.&lt;/p&gt;

&lt;p&gt;That's the core idea of a blockchain. It is a shared record that functions without a central boss. Once information is recorded, it remains there permanently because the system is designed to prevent anyone from tampering with the history. Instead of trusting a single company to keep the records straight, the system relies on math and a network of computers reaching a consensus.&lt;/p&gt;

&lt;p&gt;While this describes the initial "open and ownerless" concept, the technology has evolved to allow for managed variations like &lt;strong&gt;private&lt;/strong&gt;, &lt;strong&gt;hybrid&lt;/strong&gt;, or &lt;strong&gt;consortium&lt;/strong&gt; blockchains, where specific entities or pre-selected groups control the records rather than the general public.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does this matter?
&lt;/h2&gt;

&lt;p&gt;It shifts how we handle control and trust in our daily lives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Moving value without traditional hurdles&lt;/strong&gt;. Usually, sending money abroad involves a chain of banks. It can take days, involves various fees, and a single institution can decide to halt the transaction. Blockchain allows for more direct transfers that often settle much faster, bypassing many of the usual middlemen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agreements governed by code&lt;/strong&gt;. Think about hiring a freelancer. Rather than relying solely on a handshake or expensive legal backing, you could use a smart contract. The agreement is programmed: when the work is verified, the payment is released automatically. This reduces the need to chase invoices or worry about payment delays.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secure records of ownership&lt;/strong&gt;. Most important documents, like house deeds, are stored in centralized offices. If those records are lost, damaged, or altered by error, proving what you own becomes a nightmare. Recording ownership on a blockchain provides a decentralized backup, meaning there is no single point of failure that can wipe out your proof of property.&lt;/p&gt;

&lt;p&gt;These aren't just ideas for the future; the infrastructure to support these shifts is being built and used right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  If it's so great, why hasn't it taken over?
&lt;/h2&gt;

&lt;p&gt;To be honest, the early versions were often slow and expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bitcoin&lt;/strong&gt;, the first major implementation, can handle roughly 7 transactions per second. Compare that to Visa, which processes around 65,000. While Bitcoin was a massive breakthrough in proving the concept of decentralized trust, it wasn't originally designed for high-speed, high-volume traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ethereum&lt;/strong&gt; expanded the horizon by making the technology programmable. It allowed people to build applications and write smart contracts, but it faced similar growing pains. During busy periods, the network can get congested, causing transaction fees to spike sometimes to $50 or more. High costs like that make it difficult to use for everyday things like buying coffee or paying a small invoice.&lt;/p&gt;

&lt;p&gt;For a while, these limitations meant the tech was mostly used for speculation. People traded tokens back and forth, not necessarily because the technology lacked potential, but because the underlying infrastructure was still catching up to the demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Solana comes in
&lt;/h2&gt;

&lt;p&gt;Solana was built to address these specific bottlenecks.&lt;/p&gt;

&lt;p&gt;While many earlier blockchains struggled with low throughput, Solana was engineered to handle thousands of transactions per second. This shift makes the technology much more practical for daily use. Instead of paying dollars in fees and waiting minutes for a confirmation, transactions on Solana typically cost fractions of a cent and finalize in under a second.&lt;/p&gt;

&lt;p&gt;This performance is what allows for real-world applications beyond just trading. It opens the door for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Global payment systems&lt;/strong&gt; that rival traditional speeds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social platforms and games&lt;/strong&gt; where every interaction doesn't require a massive fee.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supply chain tracking&lt;/strong&gt; that needs to record thousands of data points in real-time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solana isn't the only high-speed network available, but it has become one of the most battle-tested. With a large developer ecosystem and a growing list of products running in production, it represents a move away from theoretical potential toward actual, scalable utility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why you should care right now
&lt;/h2&gt;

&lt;p&gt;If you are a developer, blockchain isn't a "future" skill you can indefinitely postpone. Companies are hiring for it, products are shipping on it, and those who understand the architecture now have a distinct advantage.&lt;/p&gt;

&lt;p&gt;The best part? If you know JavaScript, you already have a solid foundation. Building on Solana doesn't mean starting from scratch or throwing away your existing knowledge. Many of the core concepts map directly to the logic and systems you already understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start building
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://mlh.link/solana-100" rel="noopener noreferrer"&gt;100 Days of Solana&lt;/a&gt; is a free, daily coding challenge designed to take you from zero blockchain experience to building functional applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Format&lt;/strong&gt;: One challenge per day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Goal&lt;/strong&gt;: No prerequisites, just show up and build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Progress&lt;/strong&gt;: Last week, participants set up their first wallets, funding them with test SOL, and interacting with the network. This week, participants will learn how to read the blockchain.
By the end of the 100 days, you won't just have theoretical knowledge; you'll have a portfolio of real projects that demonstrate exactly what you can do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://mlh.link/solana-100" rel="noopener noreferrer"&gt;Join 100 Days of Solana&lt;/a&gt;&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>learning</category>
      <category>web3</category>
      <category>solana</category>
    </item>
    <item>
      <title>How AI Can Make You a 10x Software Engineer</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Thu, 14 Aug 2025 20:46:35 +0000</pubDate>
      <link>https://dev.to/janvinsha/how-ai-can-make-you-a-10x-software-engineer-1bje</link>
      <guid>https://dev.to/janvinsha/how-ai-can-make-you-a-10x-software-engineer-1bje</guid>
      <description>&lt;p&gt;In the rapidly evolving world of technology, artificial intelligence (AI) has sparked intense debates. Some predict that AI will replace software engineers entirely, while others argue that building products has become so straightforward that traditional software engineering skills are obsolete. I strongly disagree with both views. In fact, learning software engineering is more valuable than ever. With a solid foundation, you can leverage AI to handle edge cases, make informed decisions, and automate boilerplate code. This turns you into a productivity powerhouse. In this article, I'll share how I used AI to build a complex product in just three weeks (part-time), what I learned from the experience, and why skilled engineers are uniquely positioned to thrive in this AI-driven era.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Power of Experience in an AI World
&lt;/h2&gt;

&lt;p&gt;Before diving into the specifics, consider this: I'm currently working on another project where I reached a minimum viable product (MVP) in just a couple of days. Why so fast? My years of software engineering experience allowed me to architect the solution efficiently, anticipate pitfalls, and integrate AI tools seamlessly. Without that knowledge, AI alone wouldn't have sufficed. It's the synergy between human expertise and AI that creates magic.&lt;/p&gt;

&lt;p&gt;This brings me to the main story: I was tasked with building a trading academy API. This wasn't a simple app; it needed a full learning management system (LMS) for courses, channels for trading signals, direct messaging (DMs) for user interactions, and subscription management. A project of this scope would typically take several months for a solo developer. But by combining my engineering skills with AI assistance, I completed it in three weeks. And it was not even full-time. If I'd dedicated myself entirely, it could have been done in two. Here's how I did it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Laying the Foundation: Structure and Tech Choices
&lt;/h2&gt;

&lt;p&gt;Success started with thoughtful planning, drawing on my software engineering background. I knew the pros and cons of common architectures; for instance, the Model-View-Controller (MVC) pattern can lead to cluttered code in larger projects. Instead, I opted for a feature-based structure to keep things modular and scalable.&lt;/p&gt;

&lt;p&gt;I chose Node.js with Express.js for the backend to enable rapid development, paired with MongoDB for flexible data storage. Crucially, I designed the features to be loosely coupled, allowing me to build and test one at a time without ripple effects. This modularity is a hallmark of good engineering and made AI integration smoother.&lt;/p&gt;

&lt;p&gt;For each feature, I enforced a consistent structure: controllers for handling requests, services for business logic, validators for input checks, routes for API endpoints, models for data schemas, types for TypeScript definitions, and middlewares for cross-cutting concerns. I also created a shared utilities folder for reusable components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Features with AI: From Auth to Messaging
&lt;/h2&gt;

&lt;p&gt;I kicked off with authentication, a standard but critical component. Using Claude (an AI coding assistant), I generated boilerplate code for email-based auth with refresh tokens. The output was well-structured, but it had a few errors, like outdated dependencies, which I quickly fixed using my knowledge. After testing in Postman, it was solid.&lt;/p&gt;

&lt;p&gt;Next came user management. I separated the User model (focused on authentication) from the Profile model (for easily updatable user details). Again, Claude provided the CRUD (Create, Read, Update, Delete) boilerplate. I didn't accept it blindly; I reviewed for adherence to my structure, fixed issues, and ensured everything worked through rigorous testing.&lt;/p&gt;

&lt;p&gt;File management followed suit. Claude generated the code, but I spotted an outdated AWS SDK version in the output. This was a reminder that AI tools might not always reflect the latest updates. Drawing on my experience, I upgraded it, set up an AWS S3 bucket with a CDN for efficient delivery, and verified functionality.&lt;/p&gt;

&lt;p&gt;Courses were straightforward: same process, with minor error fixes leading to a working LMS module.&lt;/p&gt;

&lt;p&gt;Messaging proved trickier. Midway through, I hit Claude's chat limit. Undeterred, I had the AI generate a detailed prompt summarizing the project's state, structure, and progress. I pasted this into a new chat session, allowing the AI to pick up seamlessly. The structure shifted slightly at first, but I guided it back on track. In the end, I handled most error resolutions myself, making necessary updates to ensure robust DMs and channels.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Lessons Learned: AI as a Bootstrapper, Not a Replacement
&lt;/h2&gt;

&lt;p&gt;This project reinforced a key insight: AI excels at bootstrapping. It generates standard solutions quickly, handles repetitive tasks, and accelerates development. But it's not infallible. Errors, outdated info, and context loss require human intervention. That's where software engineering shines: knowing what to ask, spotting flaws, and refining outputs.&lt;/p&gt;

&lt;p&gt;AI has empowered engineers to become solo founders, pushing products to market at unprecedented speeds. It hasn't made us obsolete; it's elevated us to "god-like" productivity levels. Imagine completing months of work in weeks. That's the reality for those who know how to wield it. A novice "vibe coder" couldn't achieve this; only a skilled engineer can direct AI effectively, avoiding pitfalls and ensuring quality. In my case, AI shaved off boilerplate drudgery, letting me focus on architecture and innovation. The result? A fully functional trading academy API, delivered efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Embrace AI, But Build Your Foundation First
&lt;/h2&gt;

&lt;p&gt;AI isn't here to replace software engineers. It's here to amplify them. By mastering the fundamentals, you can become a 10x engineer: faster, more innovative, and capable of solo feats that once required teams. My experience proves it: leverage AI for speed, but rely on your expertise for precision.For inquiries, reach out via X at &lt;a href="https://x.com/janvinsha" rel="noopener noreferrer"&gt;@janvinsha&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Ethereum vs Solana: Understanding Data Storage Differences in Their Ecosystems</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Wed, 08 Jan 2025 19:04:30 +0000</pubDate>
      <link>https://dev.to/janvinsha/ethereum-vs-solana-understanding-data-storage-differences-in-their-ecosystems-4682</link>
      <guid>https://dev.to/janvinsha/ethereum-vs-solana-understanding-data-storage-differences-in-their-ecosystems-4682</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
In the rapidly evolving blockchain landscape, Ethereum and Solana stand out as two of the most prominent platforms, each with its unique architecture and capabilities. While both aim to facilitate decentralized applications (dApps) and smart contracts, their approaches to data storage differ significantly. Understanding these differences is crucial for developers choosing the right platform for their projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ethereum's Smart Contract Data Storage&lt;/strong&gt;&lt;br&gt;
Ethereum, the pioneer of smart contracts, allows developers to store data directly within smart contracts. This capability is intrinsic to Ethereum’s design, where each smart contract is essentially a stateful entity on the blockchain. Developers can define and manage variables within contracts, enabling complex logic and data manipulation directly on-chain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storing data within smart contracts offers several advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Simplicity and Cohesion: All related logic and data reside within the same contract, making the development process more straightforward.&lt;/li&gt;
&lt;li&gt;Atomic Transactions: Operations on data can be executed atomically, ensuring consistency and reliability.&lt;/li&gt;
&lt;li&gt;Rich Ecosystem: Ethereum’s mature tooling and extensive documentation support seamless data management within contracts.
However, this approach also has drawbacks. Storing large amounts of data on-chain can be expensive due to gas fees, and it may lead to scalability issues as the blockchain grows.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Solana’s Account-Based Data Separation&lt;/strong&gt;&lt;br&gt;
In contrast, Solana adopts a different strategy by separating data storage from program logic. Instead of embedding data within smart contracts, Solana uses separate accounts to hold data. These accounts are often Program Derived Addresses (PDAs), which are deterministic and derived from the program’s public key and specific seeds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key aspects of Solana’s data storage model include:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Modularity: By decoupling data from program logic, Solana promotes a more modular architecture. Programs can interact with multiple data accounts, enhancing flexibility.&lt;/li&gt;
&lt;li&gt;Scalability: This separation allows for more efficient data handling and reduces the overhead on individual programs, contributing to Solana’s high throughput.&lt;/li&gt;
&lt;li&gt;Security: PDAs ensure that only the designated program can modify the associated data, enhancing security through deterministic address generation.
While Solana’s approach offers scalability and modularity, it introduces complexity. Developers must manage multiple accounts and ensure proper interactions between programs and data accounts. This can increase the learning curve compared to Ethereum’s more integrated model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Comparative Insights&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Performance and Scalability: Solana’s account-based model and high throughput make it suitable for applications requiring rapid transactions and extensive data manipulation. Ethereum, while slower and less scalable, benefits from its established network and robust security features.&lt;/li&gt;
&lt;li&gt;Developer Experience: Ethereum’s all-in-one contract data storage is more intuitive for developers familiar with traditional smart contract development. Solana’s separation of data and logic requires a deeper understanding of account management and PDA utilization.&lt;/li&gt;
&lt;li&gt;Use Cases: Ethereum excels in scenarios where tight integration of logic and data is beneficial, such as decentralized finance (DeFi) protocols and complex dApps. Solana shines in high-frequency applications like gaming, real-time analytics, and NFT platforms that demand speed and scalability.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Both Ethereum and Solana offer powerful ecosystems for building decentralized applications, but their approaches to data storage reflect different priorities and architectural philosophies. Ethereum’s ability to store data within smart contracts provides simplicity and cohesion, making it ideal for a wide range of applications. On the other hand, Solana’s separation of data into PDAs and other accounts enhances scalability and performance, catering to high-throughput demands.&lt;br&gt;
For developers, the choice between Ethereum and Solana hinges on the specific requirements of their projects. Understanding these key differences in data storage is essential for leveraging each platform’s strengths and building efficient, scalable, and secure decentralized applications&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>solana</category>
      <category>blockchain</category>
      <category>web3</category>
    </item>
    <item>
      <title>A Lesson in Simplicity: Sorting Files Like a Pro in an Interview</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Tue, 29 Oct 2024 14:30:39 +0000</pubDate>
      <link>https://dev.to/janvinsha/a-lesson-in-simplicity-sorting-files-like-a-pro-in-an-interview-1nlo</link>
      <guid>https://dev.to/janvinsha/a-lesson-in-simplicity-sorting-files-like-a-pro-in-an-interview-1nlo</guid>
      <description>&lt;p&gt;During a technical interview for a full-stack developer role, I found myself in a familiar yet unexpectedly challenging situation. Everything had been going smoothly until the interviewer presented me with a task that seemed simple at first.&lt;/p&gt;

&lt;p&gt;“Can you sort these filenames the way they’d appear in a file explorer, in ascending order?” they asked.&lt;/p&gt;

&lt;p&gt;I thought, “Piece of cake.” Sorting is such a fundamental operation that I didn't expect any trouble. But as soon as I started writing the code, I hit a snag. The filenames were all over the place some were simple, but others included numbers, letters, and combinations of both.&lt;/p&gt;

&lt;p&gt;I tried using a basic string sorting method like:&lt;br&gt;
&lt;code&gt;array.sort();&lt;/code&gt;&lt;br&gt;
But this produced an odd result. The numbers were sorted lexicographically (meaning “10” would come before “2” because it starts with a “1”), and mixed alphanumeric strings weren’t in the correct order. It was a mess, and it didn’t resemble the natural order you see in file explorers at all.&lt;/p&gt;

&lt;p&gt;I could feel the clock ticking and pressure building up. I tried to work through various custom comparison functions to handle the numbers properly, but nothing seemed to click.&lt;/p&gt;

&lt;p&gt;Then, I remembered a simple trick I had read about not too long ago: localeCompare.&lt;/p&gt;

&lt;p&gt;localeCompare allows you to compare strings in a way that mimics how humans sort things. By using it with the numeric option, it handles the numbers as actual numbers rather than comparing them as text. Here’s the code I used:&lt;br&gt;
&lt;code&gt;array.sort((a, b) =&amp;gt; a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }));&lt;/code&gt;&lt;br&gt;
This single line of code sorted the filenames exactly like a file explorer would: numbers were ordered naturally, and letter/number combinations were handled seamlessly.&lt;/p&gt;

&lt;p&gt;As soon as I ran the code, I saw the correct order appear on the screen. The filenames were perfectly sorted in ascending order, just like in a file explorer. I smiled as I explained the solution to the interviewer, who seemed pleased with how I resolved the issue.&lt;/p&gt;

&lt;p&gt;What initially felt like a complicated problem ended up being solved with a simple, elegant solution. It was a reminder that sometimes the most effective tools are the simplest, and knowing those small tricks can make all the difference.&lt;/p&gt;

</description>
      <category>interview</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>career</category>
    </item>
    <item>
      <title>Debugging WebSocket Connection Failure: wss://relay.walletconnect.org</title>
      <dc:creator>Vincent Jande</dc:creator>
      <pubDate>Thu, 24 Oct 2024 15:01:34 +0000</pubDate>
      <link>https://dev.to/janvinsha/debugging-websocket-connection-failure-wssrelaywalletconnectorg-3hnc</link>
      <guid>https://dev.to/janvinsha/debugging-websocket-connection-failure-wssrelaywalletconnectorg-3hnc</guid>
      <description>&lt;p&gt;If you've encountered a WebSocket connection failure when trying to use WalletConnect with an error like:&amp;nbsp;&lt;br&gt;
&lt;strong&gt;WebSocket connection to 'wss://relay.walletconnect.org' failed&lt;/strong&gt;&lt;br&gt;
this error might be linked to access restrictions applied by certain services to specific countries, including Nigeria.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding WebSocket and WalletConnect
&lt;/h3&gt;

&lt;p&gt;WalletConnect is an open protocol for connecting decentralized applications (dApps) to mobile wallets through QR code scanning or deep linking. It relies on WebSocket (WS) connections to relay encrypted communication between the dApp and the wallet. The WebSocket protocol, denoted by the wss:// scheme (secure WebSocket), is crucial for maintaining a persistent connection between the client and server for real-time interactions.&lt;br&gt;
However, you might encounter the WebSocket failure for the relay.walletconnect.org endpoint due to geo-blocking. Some platforms, including WalletConnect's relayer, restrict access to certain countries like Nigeria, potentially due to regulatory compliance or risk management strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Symptoms
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Connection Timeout or Failure&lt;/strong&gt;: When initiating the connection to wss://relay.walletconnect.org, the WebSocket handshake fails.&lt;br&gt;
&lt;strong&gt;Inconsistent Behavior&lt;/strong&gt;: The issue may persist across different networks and devices in Nigeria but may work without problems when using a VPN or accessing the service from a different location.&lt;br&gt;
&lt;strong&gt;Country-Specific Restrictions&lt;/strong&gt;: WalletConnect's relay servers could be enforcing geo-blocks, resulting in connection denials for users based in regions with restricted access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workarounds
&lt;/h3&gt;

&lt;p&gt;If you're facing this error, there are a few options to explore:&lt;br&gt;
&lt;strong&gt;Use a VPN&lt;/strong&gt;: A simple but effective solution is using a VPN to connect from a country where WebSocket connections to WalletConnect relayers are not blocked.&lt;br&gt;
&lt;strong&gt;Proxy Services&lt;/strong&gt;: Set up a proxy server in an unrestricted region to relay the WebSocket connection on your behalf.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In conclusion&lt;/strong&gt;, this issue highlights the importance of understanding country-specific restrictions when developing or using Web3 tools. While frustrating, using a VPN or alternative relayer services can help you work around the problem.&lt;/p&gt;

</description>
      <category>wagmi</category>
      <category>react</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
  </channel>
</rss>
