<?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: Peter Okoh</title>
    <description>The latest articles on DEV Community by Peter Okoh (@peter_okoh_).</description>
    <link>https://dev.to/peter_okoh_</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%2F3911937%2Fcc561586-d513-4c33-8dd0-92c70522ef04.jpg</url>
      <title>DEV Community: Peter Okoh</title>
      <link>https://dev.to/peter_okoh_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/peter_okoh_"/>
    <language>en</language>
    <item>
      <title>Day 76 #100daysofsolana: The CPI Mental Model I Wish I Had on Day 71</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Fri, 24 Jul 2026 12:08:26 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/day-76-100daysofsolana-the-cpi-mental-model-i-wish-i-had-on-day-71-3di5</link>
      <guid>https://dev.to/peter_okoh_/day-76-100daysofsolana-the-cpi-mental-model-i-wish-i-had-on-day-71-3di5</guid>
      <description>&lt;p&gt;When I started learning Solana, &lt;strong&gt;Cross-Program Invocation (CPI)&lt;/strong&gt; sounded far more complicated than it actually is.&lt;/p&gt;

&lt;p&gt;I kept seeing &lt;code&gt;CpiContext&lt;/code&gt;, &lt;code&gt;invoke_signed&lt;/code&gt;, program IDs, account structs, and signer seeds everywhere. I could copy the examples, but if someone had asked me what was really happening under the hood, I probably wouldn't have had a good answer.&lt;/p&gt;

&lt;p&gt;A few days later, after building a vault program, making one program call another, and intentionally breaking my own code just to understand the errors, everything finally clicked.&lt;/p&gt;

&lt;p&gt;If I could go back to Day 71 and explain CPI to myself in one sentence, it would be this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A CPI is just one Solana program asking another program to do some work, but it must bring the right program, the right accounts, and the right signer.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That simple idea made everything else easier to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model that finally made sense
&lt;/h2&gt;

&lt;p&gt;Coming from Web2, I started thinking of a CPI like calling a function from another module.&lt;/p&gt;

&lt;p&gt;Except on Solana, you can't just call the function.&lt;/p&gt;

&lt;p&gt;You have to arrive with three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The program you want to call&lt;/strong&gt; (identified by its Program ID).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every account that program expects&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who has the authority to approve the action&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Miss any one of those, and the runtime immediately complains.&lt;/p&gt;

&lt;p&gt;That's really all a &lt;code&gt;CpiContext&lt;/code&gt; is doing.&lt;/p&gt;

&lt;p&gt;It packages those three pieces together before handing execution over to another program.&lt;/p&gt;

&lt;p&gt;Once I stopped seeing &lt;code&gt;CpiContext&lt;/code&gt; as some mysterious Anchor feature and started seeing it as a container for &lt;strong&gt;"who, what, and with what authority,"&lt;/strong&gt; the code became much easier to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real example from my project
&lt;/h2&gt;

&lt;p&gt;One of the exercises I built this week was a simple program that calls another program to increment a counter.&lt;/p&gt;

&lt;p&gt;The handler was surprisingly small:&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;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;bump&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;Bump&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;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cpi_ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CpiContext&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="py"&gt;.accounts.counter_program&lt;/span&gt;&lt;span class="nf"&gt;.key&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nn"&gt;compose_lab&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cpi&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Increment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;tally&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.tally&lt;/span&gt;&lt;span class="nf"&gt;.to_account_info&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="nn"&gt;compose_lab&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cpi&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cpi_ctx&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="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;There isn't much happening here.&lt;/p&gt;

&lt;p&gt;The caller simply says:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Here's the program I want to call."&lt;/li&gt;
&lt;li&gt;"Here's the account it needs."&lt;/li&gt;
&lt;li&gt;"Go execute its &lt;code&gt;increment&lt;/code&gt; instruction."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Earlier in the week, I also built a vault where a &lt;strong&gt;PDA signed on behalf of the program&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That was another moment where things finally clicked.&lt;/p&gt;

&lt;p&gt;A PDA doesn't have a private key sitting somewhere waiting to sign a transaction.&lt;/p&gt;

&lt;p&gt;Instead, the runtime recomputes the PDA using the same seeds and bump your program provides. If they match the PDA's address, the runtime treats that PDA as an authorized signer.&lt;/p&gt;

&lt;p&gt;That made &lt;code&gt;invoke_signed()&lt;/code&gt; feel a lot less magical.&lt;/p&gt;

&lt;h2&gt;
  
  
  What tripped me up
&lt;/h2&gt;

&lt;p&gt;One of the best parts of this week's challenge was intentionally breaking working code.&lt;/p&gt;

&lt;p&gt;I changed the PDA seeds.&lt;/p&gt;

&lt;p&gt;I changed account constraints.&lt;/p&gt;

&lt;p&gt;I even pointed a CPI at the &lt;strong&gt;System Program&lt;/strong&gt; instead of my own program.&lt;/p&gt;

&lt;p&gt;Each failure taught me something different.&lt;/p&gt;

&lt;p&gt;One error I saw was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error Code: ConstraintSeeds.
Error Message: A seeds constraint was violated.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance it looked intimidating.&lt;/p&gt;

&lt;p&gt;But after slowing down and reading it, the message was actually telling me exactly what was wrong.&lt;/p&gt;

&lt;p&gt;The PDA the caller passed didn't match the PDA the callee expected.&lt;/p&gt;

&lt;p&gt;Later, I intentionally pointed my CPI to the System Program and got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Program 11111111111111111111111111111111 failed:
invalid instruction data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That wasn't because my instruction was bad.&lt;/p&gt;

&lt;p&gt;It was because I had sent perfectly valid instruction data to the &lt;strong&gt;wrong program&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once I understood what each error was trying to tell me, debugging became much less frustrating.&lt;/p&gt;

&lt;p&gt;Instead of random red text, the logs started feeling like clues.&lt;/p&gt;

&lt;h2&gt;
  
  
  My biggest takeaway
&lt;/h2&gt;

&lt;p&gt;Looking back, CPI wasn't the hard part.&lt;/p&gt;

&lt;p&gt;The hard part was trying to understand the code before I understood the mental model.&lt;/p&gt;

&lt;p&gt;Once I realized every CPI comes down to &lt;strong&gt;the program, the accounts, and the signer&lt;/strong&gt;, everything else started fitting together.&lt;/p&gt;

&lt;p&gt;Even the errors became useful.&lt;/p&gt;

&lt;p&gt;That's probably the biggest lesson I've learned so far in this Solana journey.&lt;/p&gt;

&lt;h1&gt;
  
  
  100daysofsolana
&lt;/h1&gt;

</description>
      <category>solana</category>
      <category>rust</category>
      <category>anchor</category>
      <category>web3</category>
    </item>
    <item>
      <title>Day 69 #100daysofsolana: What a Week of Building on Solana Taught Me About Program Derived Addresses (PDAs)</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Wed, 22 Jul 2026 20:26:36 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/day-69-100daysofsolana-what-a-week-of-building-on-solana-taught-me-about-program-derived-2jel</link>
      <guid>https://dev.to/peter_okoh_/day-69-100daysofsolana-what-a-week-of-building-on-solana-taught-me-about-program-derived-2jel</guid>
      <description>&lt;p&gt;When I first heard about Program Derived Addresses (PDAs), they sounded like one of those Solana concepts that everyone claims are simple until you actually have to use them. After spending the past week building a counter program with Anchor, breaking things on purpose, fixing them, and watching transactions fail for reasons I didn't understand at first, I can finally say I have a mental model that makes sense.&lt;/p&gt;

&lt;p&gt;If you're coming from a Web2 background like I am, I hope this saves you a few hours of confusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do PDAs even exist?
&lt;/h2&gt;

&lt;p&gt;One thing I learned early is that Solana programs don't store state the way a traditional backend application does. If your program needs to remember something, whether it's a user's profile, a game score, a counter, or a configuration, it needs a predictable account where that data lives.&lt;/p&gt;

&lt;p&gt;That's exactly what a PDA gives you.&lt;/p&gt;

&lt;p&gt;Think of it like a database primary key that can always be computed again. Instead of storing an address somewhere and looking it up later, your program derives it whenever it needs it.&lt;/p&gt;

&lt;p&gt;The difference is that this address isn't random. It's derived from your program's seeds and your program ID, meaning the same inputs will always produce the same PDA.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model that finally clicked
&lt;/h2&gt;

&lt;p&gt;The analogy that helped me most was this:&lt;/p&gt;

&lt;p&gt;Imagine a users table in a database.&lt;/p&gt;

&lt;p&gt;Instead of looking up a row using an auto-increment ID, imagine you could always calculate the row's primary key from something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the application&lt;/li&gt;
&lt;li&gt;the user's wallet address&lt;/li&gt;
&lt;li&gt;a fixed prefix&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's basically what PDAs feel like.&lt;/p&gt;

&lt;p&gt;Except there isn't actually a database.&lt;/p&gt;

&lt;p&gt;The Solana account model is the storage layer, and PDAs are deterministic addresses that your program can always derive whenever it needs them.&lt;/p&gt;

&lt;p&gt;Another important thing I learned is that deriving a PDA doesn't automatically create an account.&lt;/p&gt;

&lt;p&gt;You can derive thousands of PDAs that don't exist yet. An account only comes into existence after your program initializes it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking down my own PDA
&lt;/h2&gt;

&lt;p&gt;This is the pattern I used in my counter program.&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;#[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;user,&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;user&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what each piece does.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;b"counter"&lt;/code&gt; is a static seed that identifies what kind of PDA this is.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user.key().as_ref()&lt;/code&gt; makes the PDA unique for each wallet.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;seeds&lt;/code&gt; are combined with the program ID to derive the address.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bump&lt;/code&gt; is the extra byte Anchor finds to make sure the resulting address falls off the Ed25519 curve.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last part confused me for a while.&lt;/p&gt;

&lt;p&gt;The bump isn't magic. Anchor simply tries different bump values until it finds one that produces a valid PDA. Once it finds it, that's the canonical bump you should keep using.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why your seeds matter
&lt;/h2&gt;

&lt;p&gt;One of my biggest lessons came from intentionally changing my seeds and watching what happened.&lt;/p&gt;

&lt;p&gt;Using:&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="n"&gt;seeds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;b"counter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="nf"&gt;.key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;gave every wallet its own counter.&lt;/p&gt;

&lt;p&gt;Changing it to:&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="n"&gt;seeds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;b"counter"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;meant everyone derived exactly the same PDA.&lt;/p&gt;

&lt;p&gt;Neither approach is wrong.&lt;/p&gt;

&lt;p&gt;It depends entirely on what you're building.&lt;/p&gt;

&lt;p&gt;A global configuration account? A shared PDA is perfect.&lt;/p&gt;

&lt;p&gt;A personal counter for every user?&lt;/p&gt;

&lt;p&gt;A shared PDA becomes a disaster because everyone writes to the same account.&lt;/p&gt;

&lt;p&gt;That experiment made the purpose of seeds much clearer than any documentation I had read.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the bump actually buys you
&lt;/h2&gt;

&lt;p&gt;The bump exists because not every derived address can safely become a PDA.&lt;/p&gt;

&lt;p&gt;Anchor searches for the canonical bump value that works and stores it for you when you write:&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="n"&gt;bump&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later instructions can simply reuse the stored bump instead of recalculating it every time.&lt;/p&gt;

&lt;p&gt;It's a small optimization, but it's also cleaner and less error-prone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lifecycle of a PDA
&lt;/h2&gt;

&lt;p&gt;Over the past week, I noticed that every PDA in my project followed the same lifecycle.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Derive the PDA from seeds.&lt;/li&gt;
&lt;li&gt;Initialize the account with &lt;code&gt;init&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Read or update its data whenever needed.&lt;/li&gt;
&lt;li&gt;Close the account when it's no longer useful.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Closing a PDA was another interesting lesson.&lt;/p&gt;

&lt;p&gt;Coming from Web2, I kept thinking of it as deleting a database row.&lt;/p&gt;

&lt;p&gt;It isn't.&lt;/p&gt;

&lt;p&gt;Closing an account transfers its rent back to a recipient, clears the data, and marks the account for cleanup once the transaction finishes.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2pox08ggq3jxacdef2gk.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2pox08ggq3jxacdef2gk.png" alt=" " width="798" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a subtle difference, but understanding it helped me appreciate how Solana manages accounts under the hood.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell myself on Day 64
&lt;/h2&gt;

&lt;p&gt;If I could go back to when I started this project, I'd probably leave myself these notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your program ID is part of every PDA derivation. The same seeds in another program produce a completely different address.&lt;/li&gt;
&lt;li&gt;A PDA cannot sign transactions by itself. Your program signs on its behalf using the same seeds.&lt;/li&gt;
&lt;li&gt;Seeds determine your data model. Think carefully before choosing them.&lt;/li&gt;
&lt;li&gt;Don't treat &lt;code&gt;init_if_needed&lt;/code&gt; as your default solution. It's useful, but it's easy to misuse if you don't fully understand when accounts should already exist.&lt;/li&gt;
&lt;li&gt;Breaking things on purpose taught me more than reading another tutorial ever did.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This week wasn't just about building a counter program.&lt;/p&gt;

&lt;p&gt;It was about understanding how Solana thinks about state.&lt;/p&gt;

&lt;p&gt;PDAs stopped feeling like some cryptographic trick and started feeling like a practical design tool. Once that mental model clicked, the rest of my Anchor code became much easier to reason about.&lt;/p&gt;

&lt;p&gt;I'm still learning, but I can already tell this is one of those concepts that changes how you design Solana programs.&lt;/p&gt;

&lt;p&gt;If you're learning PDAs too, I'd recommend reading the official Solana PDA documentation alongside the Anchor PDA guide, then building something simple and deliberately changing the seeds to see what breaks. That's the exercise that made everything click for me.&lt;/p&gt;

&lt;h1&gt;
  
  
  100DaysOfSolana
&lt;/h1&gt;

</description>
      <category>solana</category>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Day 62 #100daysofsolana: How I Built My First Anchor Counter Program and Learned to Trust My Tests</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Sat, 18 Jul 2026 10:59:39 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/day-62-100daysofsolana-how-i-built-my-first-anchor-counter-program-and-learned-to-trust-my-tests-4o6e</link>
      <guid>https://dev.to/peter_okoh_/day-62-100daysofsolana-how-i-built-my-first-anchor-counter-program-and-learned-to-trust-my-tests-4o6e</guid>
      <description>&lt;p&gt;There's something satisfying about seeing your tests pass after spending days building, breaking, fixing, and rebuilding the same program.&lt;/p&gt;

&lt;p&gt;Over the past week, I worked on a simple counter program with Anchor. At first glance, it doesn't look like much, it just initializes a counter and increments it. But behind those few lines of code are some important lessons about Solana programs, account validation, and why good tests matter.&lt;/p&gt;

&lt;p&gt;The first thing that stood out to me was the &lt;code&gt;Initialize&lt;/code&gt; accounts struct. Coming from a more traditional development background, it took me a while to appreciate that most of the "magic" in Anchor happens before your instruction logic even runs. The accounts struct defines exactly which accounts are needed, who owns them, who pays for them, and what constraints must be satisfied. Once I understood that, the rest of the program started making a lot more sense.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;initialize&lt;/code&gt; handler itself is surprisingly short. That's because &lt;code&gt;ctx.accounts&lt;/code&gt; gives you direct access to all the validated accounts you declared earlier. Instead of writing lots of validation logic yourself, Anchor handles it for you. All the handler needs to do is set the initial value of the counter.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;increment&lt;/code&gt; instruction taught me another valuable lesson. By adding an account constraint that checks the authority, I learned that security doesn't always belong inside the function body. Anchor verifies those constraints before the instruction executes, preventing unauthorized users from incrementing someone else's counter. That small addition made me appreciate how much safer programs can become when validation is built into the framework.&lt;/p&gt;

&lt;p&gt;Writing the tests was where everything really clicked.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3iwzzw00xquexdsie49z.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3iwzzw00xquexdsie49z.png" alt=" " width="800" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The happy-path test confirmed that a newly initialized counter starts with the expected value and increments correctly. If that test ever fails, it means the program's core functionality is broken.&lt;/p&gt;

&lt;p&gt;The unauthorized increment test became my favorite. It attempts to increment a counter using the wrong wallet and expects the transaction to fail. If that test unexpectedly passes, it means anyone could modify someone else's counter, a serious security flaw. That single test gave me much more confidence in the program.&lt;/p&gt;

&lt;p&gt;One of the most eye-opening exercises was intentionally introducing bugs into the code. For one experiment, I changed:&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="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;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&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="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;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I expected everything to compile, and it did. But my tests immediately failed because the final counter value was no longer what the assertions expected.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff0yfzlr0xojgk0ooga9x.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff0yfzlr0xojgk0ooga9x.png" alt=" " width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That moment reinforced an important lesson for me: passing compilation doesn't mean your program is correct. Tests are what prove your code behaves the way you intended.&lt;/p&gt;

&lt;p&gt;This project may be a simple counter, but it taught me much more than incrementing numbers. It helped me understand how Anchor validates accounts, how instruction handlers stay clean because of those validations, and why writing failure-path tests is just as important as testing successful transactions.&lt;/p&gt;

&lt;p&gt;If I had another week to improve this project, I'd explore custom error codes, event logging, Program Derived Addresses (PDAs), and more advanced account relationships to better understand how real-world Solana programs are structured.&lt;/p&gt;

&lt;p&gt;Small projects often teach the biggest lessons.&lt;/p&gt;

&lt;h1&gt;
  
  
  100DaysOfSolana #Solana #Anchor #Rust #Testing #BuildInPublic
&lt;/h1&gt;

</description>
      <category>solana</category>
      <category>100daysofsolana</category>
      <category>blockchain</category>
      <category>web3</category>
    </item>
    <item>
      <title>DAY 55 #100DaysOfSolana: Three Token-2022 Mints in One Week: Transfer Fees, Interest-Bearing Tokens, and Soulbound Assets</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Tue, 30 Jun 2026 15:40:30 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/day-55-100daysofsolana-three-token-2022-mints-in-one-week-transfer-fees-interest-bearing-3aah</link>
      <guid>https://dev.to/peter_okoh_/day-55-100daysofsolana-three-token-2022-mints-in-one-week-transfer-fees-interest-bearing-3aah</guid>
      <description>&lt;p&gt;Coming from Web2, I used to think a token was just a balance in a database. If you wanted extra behavior—transaction fees, rewards, or restrictions, you'd probably build it into your application logic.&lt;/p&gt;

&lt;p&gt;Token-2022 changed that perspective for me. It's the upgraded SPL Token Program that lets you attach &lt;strong&gt;extensions&lt;/strong&gt; directly to a token mint. I like to think of these extensions as middleware. Instead of creating an entirely new token standard, you opt into the features your application needs while keeping the same underlying protocol. This week, I experimented with three different extensions, and each one completely changed how I think about designing tokens on Solana.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Transfer Fee Extension
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flwjmburljm64kco2t7yk.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flwjmburljm64kco2t7yk.png" alt=" " width="799" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the mint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spl-token create-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--program-id&lt;/span&gt; TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--decimals&lt;/span&gt; 6 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--transfer-fee-basis-points&lt;/span&gt; 100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--transfer-fee-maximum-fee&lt;/span&gt; 1000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After minting tokens, I transferred &lt;strong&gt;1,000 tokens&lt;/strong&gt; to another wallet.&lt;/p&gt;

&lt;p&gt;Something interesting happened.&lt;/p&gt;

&lt;p&gt;The recipient didn't receive 1,000 tokens.&lt;/p&gt;

&lt;p&gt;Instead, the balance became:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Balance: 990
Transfer fees withheld: 10000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remaining tokens were automatically withheld as transfer fees by the token program itself.&lt;/p&gt;

&lt;p&gt;Later, I withdrew the withheld fees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spl-token withdraw-withheld-tokens &lt;span class="nv"&gt;$MY_TA&lt;/span&gt; &lt;span class="nv"&gt;$RECIPIENT_TA&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Balance: 1000
Transfer fees withheld: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watching the fee move through the system automatically made the feature click for me.&lt;/p&gt;

&lt;h3&gt;
  
  
  When would I actually use this?
&lt;/h3&gt;

&lt;p&gt;This extension makes perfect sense for a community token or creator economy where every transfer contributes a small percentage to a project treasury. Instead of relying on off-chain accounting, the token program enforces the fee every single time.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Interest-Bearing Extension
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4yg2fapbu3xd9dpbr8m3.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4yg2fapbu3xd9dpbr8m3.png" alt=" " width="799" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the mint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spl-token create-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--program-id&lt;/span&gt; TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--decimals&lt;/span&gt; 6 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--transfer-fee-basis-points&lt;/span&gt; 100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--transfer-fee-maximum-fee&lt;/span&gt; 1000000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--interest-rate&lt;/span&gt; 5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After minting tokens, I checked the balance twice, about 30 seconds apart.&lt;/p&gt;

&lt;p&gt;The displayed balance changed from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1000062.476727
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1000062.967937
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was unexpected.&lt;/p&gt;

&lt;p&gt;At first, I assumed new tokens were being minted.&lt;/p&gt;

&lt;p&gt;They weren't.&lt;/p&gt;

&lt;p&gt;The Interest-Bearing extension **does not create additional supply.&lt;/p&gt;

&lt;p&gt;Instead, it updates the &lt;strong&gt;displayed UI amount&lt;/strong&gt; using the configured interest rate while the underlying token supply remains unchanged. That distinction is subtle, but it's an important one because it changes how you think about accounting and token economics.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Non-Transferable (Soul-Bound) Token
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F01seqahtprlikzoidora.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F01seqahtprlikzoidora.png" alt=" " width="799" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the mint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spl-token create-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--program-2022&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--enable-non-transferable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I minted one token to my wallet and then created another wallet to test whether I could transfer it.&lt;/p&gt;

&lt;p&gt;Naturally, I expected the transfer to work.&lt;/p&gt;

&lt;p&gt;It didn't.&lt;/p&gt;

&lt;p&gt;Running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spl-token transfer &lt;span class="nv"&gt;$MINT&lt;/span&gt; 1 &lt;span class="nv"&gt;$RECIPIENT&lt;/span&gt; &lt;span class="nt"&gt;--allow-unfunded-recipient&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Program log: Transfer is disabled for this mint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single error message perfectly demonstrates the purpose of this extension.&lt;/p&gt;

&lt;p&gt;Once a token is marked as non-transferable, ownership cannot simply be passed around like a regular SPL token.&lt;/p&gt;

&lt;p&gt;I immediately started thinking about applications like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;digital certificates&lt;/li&gt;
&lt;li&gt;university credentials&lt;/li&gt;
&lt;li&gt;employee IDs&lt;/li&gt;
&lt;li&gt;membership badges&lt;/li&gt;
&lt;li&gt;proof-of-attendance tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are assets that represent identity rather than value, so allowing them to be traded would defeat their purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This week completely changed how I think about tokens on Solana.&lt;/p&gt;

&lt;p&gt;Before Token-2022, I imagined every special token behavior required a custom smart contract. Instead, I learned that many of these capabilities already exist as modular extensions you can opt into when creating a mint.&lt;/p&gt;

&lt;p&gt;The Transfer Fee extension showed me how protocol-level fees can replace application logic. The Interest-Bearing extension taught me the difference between changing displayed balances and changing token supply. And the Non-Transferable extension demonstrated how the token program itself can enforce ownership rules without any additional code.&lt;/p&gt;

&lt;p&gt;If I were building a real product today, I'd happily reach for these extensions instead of reinventing them. That's probably the biggest lesson I've taken away from this part of my Solana journey: sometimes the best engineering decision isn't writing more code, it's knowing which features the platform already gives you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is part of my &lt;strong&gt;#100DaysOfSolana&lt;/strong&gt; journey. If you're exploring Solana from a Web2 background, I hope this saves you a few hours of experimentation. Feel free to connect or share what you're building, I'd love to learn from your experience too.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>solana</category>
    </item>
    <item>
      <title>Week 7: #100DaysOfSolana: What I Learned Minting NFTs on Solana with Token Extensions</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Mon, 29 Jun 2026 15:08:57 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/week-7-100daysofsolana-what-i-learned-minting-nfts-on-solana-with-token-extensions-4c5l</link>
      <guid>https://dev.to/peter_okoh_/week-7-100daysofsolana-what-i-learned-minting-nfts-on-solana-with-token-extensions-4c5l</guid>
      <description>&lt;p&gt;Before this week, I assumed creating NFTs on Solana meant using Metaplex. That was the mental model I had carried for a while.&lt;/p&gt;

&lt;p&gt;It turns out you can mint a complete NFT, with metadata, collection membership, and on-chain verification, using Solana's Token Extensions. That completely changed how I think about NFTs on Solana.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Mental Model
&lt;/h1&gt;

&lt;p&gt;One of the biggest lessons I learned this week is that an NFT on Solana isn't magic.&lt;/p&gt;

&lt;p&gt;At its core, it's simply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A token mint with a total supply of 1&lt;/li&gt;
&lt;li&gt;0 decimals, making it indivisible&lt;/li&gt;
&lt;li&gt;Metadata attached through the Metadata Extension&lt;/li&gt;
&lt;li&gt;Optionally grouped into a collection using the Group and Member extensions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I understood that, everything else started making sense. Instead of seeing NFTs as a special asset type, I started seeing them as standard tokens with a few carefully chosen extensions.&lt;/p&gt;

&lt;p&gt;That shift alone made the entire architecture much easier to understand.&lt;/p&gt;

&lt;h1&gt;
  
  
  What I Built
&lt;/h1&gt;

&lt;p&gt;Over the past few days, I built my first NFT entirely with Token Extensions.&lt;/p&gt;

&lt;p&gt;The journey included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a mint with supply 1&lt;/li&gt;
&lt;li&gt;Attaching on-chain metadata&lt;/li&gt;
&lt;li&gt;Adding the NFT to a collection using the Group and Member extensions&lt;/li&gt;
&lt;li&gt;Auditing every byte stored on-chain&lt;/li&gt;
&lt;li&gt;Updating the metadata on Devnet to understand how mutable NFTs work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seeing everything reflected on Solana Explorer after each step made the process feel much more real than simply reading documentation.&lt;/p&gt;

&lt;p&gt;One of the commands that stood out during the process was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spl-token initialize-metadata &lt;span class="se"&gt;\&lt;/span&gt;
  &amp;lt;MINT_ADDRESS&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"My First NFT"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"MNFT"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://example.com/metadata.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watching the metadata become part of the mint itself was one of those "now I get it" moments.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Surprised Me
&lt;/h1&gt;

&lt;p&gt;Coming from a Web2 background, I expected NFTs to involve a lot of custom infrastructure.&lt;/p&gt;

&lt;p&gt;Instead, I discovered that much of the functionality comes directly from Token Extensions.&lt;/p&gt;

&lt;p&gt;I also expected metadata to be something hidden behind another protocol. Instead, I learned that it can live directly on the mint account.&lt;/p&gt;

&lt;p&gt;Another surprise was how transparent everything is.&lt;/p&gt;

&lt;p&gt;Every instruction, every account, every byte of metadata can be inspected on-chain. I even wrote an audit script to verify exactly what had been stored.&lt;/p&gt;

&lt;p&gt;That level of visibility makes debugging far less mysterious than I initially expected.&lt;/p&gt;

&lt;h1&gt;
  
  
  What I'd Build Next
&lt;/h1&gt;

&lt;p&gt;Now that I understand how Token Extensions fit together, there are a few things I'm excited to explore next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building an NFT minting application with a simple frontend&lt;/li&gt;
&lt;li&gt;Experimenting with immutable metadata&lt;/li&gt;
&lt;li&gt;Creating collection management tools&lt;/li&gt;
&lt;li&gt;Exploring programmable NFTs and compressed NFTs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This week gave me a much stronger mental model of how NFTs actually work on Solana, and that's far more valuable than simply knowing the commands.&lt;/p&gt;

&lt;p&gt;The biggest takeaway wasn't learning how to mint an NFT.&lt;/p&gt;

&lt;p&gt;It was understanding what an NFT really is.&lt;/p&gt;

&lt;p&gt;For any Web2 developer curious about Solana, I'd encourage you to spend time learning Token Extensions before reaching for higher-level frameworks. Understanding the foundation makes everything else much easier.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is part of my #100DaysOfSolana journey. If you're learning Solana too, I'd love to connect and hear what you're building.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>solana</category>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Week 5 #100DaysOfSolana: Not Just Minting Tokens Anymore, Building Systems</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Fri, 29 May 2026 11:46:43 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/week-5-100daysofsolana-not-just-minting-tokens-anymore-building-systems-4ip8</link>
      <guid>https://dev.to/peter_okoh_/week-5-100daysofsolana-not-just-minting-tokens-anymore-building-systems-4ip8</guid>
      <description>&lt;p&gt;Today felt less like “following tutorials” and more like actually becoming a builder.&lt;/p&gt;

&lt;p&gt;I just built a complete token from scratch in one sitting.&lt;/p&gt;

&lt;p&gt;Metadata.&lt;br&gt;
Minting.&lt;br&gt;
Transfers.&lt;br&gt;
Transfer fees.&lt;br&gt;
Everything tied together into one working flow.&lt;/p&gt;

&lt;p&gt;And the best part?&lt;br&gt;
I wasn’t trying to learn something new today.&lt;/p&gt;

&lt;p&gt;I was proving to myself that I could connect everything I’ve learned over the past few days without relying on step-by-step guidance.&lt;/p&gt;

&lt;p&gt;That feeling hits differently.&lt;/p&gt;

&lt;p&gt;What continues to amaze me about Solana is how much infrastructure the protocol already provides.&lt;/p&gt;

&lt;p&gt;In Web2, building something like this would mean setting up databases for balances, APIs for transfers, payment systems for fees, and backend logic to connect everything together.&lt;/p&gt;

&lt;p&gt;But on Solana, the mint itself carries the configuration.&lt;br&gt;
The Token Extensions Program enforces the rules.&lt;br&gt;
Metadata lives directly on-chain.&lt;/p&gt;

&lt;p&gt;And somehow… all of that came together through a few CLI commands.&lt;/p&gt;

&lt;p&gt;Today reinforced something important for me:&lt;br&gt;
Creating, configuring, minting, transferring, and collecting fees isn’t just a random exercise.&lt;/p&gt;

&lt;p&gt;It’s a real pattern.&lt;br&gt;
A real workflow.&lt;/p&gt;

&lt;p&gt;And I can already see how this foundation leads into building more complex systems later on.&lt;/p&gt;

&lt;p&gt;Still learning.&lt;br&gt;
Still experimenting.&lt;br&gt;
But for the first time, I genuinely feel like I’m building with intention instead of just copying commands.&lt;/p&gt;

&lt;h1&gt;
  
  
  Day32
&lt;/h1&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%2F5cw6or2w4533dzfg1pbx.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%2F5cw6or2w4533dzfg1pbx.png" alt="oImage description" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>solana</category>
      <category>100daysofsolana</category>
    </item>
    <item>
      <title>From Web2 Complexity to On-Chain Simplicity</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Fri, 22 May 2026 10:24:23 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/from-web2-complexity-to-on-chain-simplicity-llp</link>
      <guid>https://dev.to/peter_okoh_/from-web2-complexity-to-on-chain-simplicity-llp</guid>
      <description>&lt;p&gt;Today’s Solana learning unlocked a new level for me.&lt;/p&gt;

&lt;p&gt;I just created a token where the transfer fee is enforced directly by the Token-2022 Program itself.&lt;/p&gt;

&lt;p&gt;Not by some backend script.&lt;br&gt;
Not by middleware.&lt;br&gt;
Not by an API quietly calculating charges behind the scenes.&lt;/p&gt;

&lt;p&gt;The logic lives on-chain.&lt;/p&gt;

&lt;p&gt;That means every valid transfer follows the same fee rules automatically, and if the expected fee is wrong, the transaction simply fails.&lt;/p&gt;

&lt;p&gt;What really amazed me is how much complexity this removes.&lt;/p&gt;

&lt;p&gt;In Web2, implementing transaction fees usually means building payment logic, handling edge cases, tracking deductions, worrying about rounding errors, and making sure nobody bypasses the system.&lt;/p&gt;

&lt;p&gt;But here, the fee configuration is part of the mint itself.&lt;br&gt;
Once set, the program handles the rest.&lt;/p&gt;

&lt;p&gt;Even the withheld fees are transparent on-chain and can later be withdrawn by the designated authority. Everything is visible. Everything is verifiable.&lt;/p&gt;

&lt;p&gt;The more I learn about Solana, the more I realise blockchain development is not just about “sending tokens".&lt;/p&gt;

&lt;p&gt;It’s about building systems where trust is enforced by code and protocol rules, not by hidden backend logic.&lt;/p&gt;

&lt;p&gt;And honestly, the fact that all of this only took a few CLI commands still blows my mind.&lt;/p&gt;

&lt;h1&gt;
  
  
  Day31
&lt;/h1&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%2Ff41e0hlj9j2jj6158z4i.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%2Ff41e0hlj9j2jj6158z4i.png" alt=" " width="800" height="174"&gt;&lt;/a&gt;&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%2Fc241nhmn434vxav9tsjy.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%2Fc241nhmn434vxav9tsjy.png" alt=" " width="800" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>solana</category>
    </item>
    <item>
      <title>My Experience Building My First Token And Having it Exist On-Chain.</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Thu, 21 May 2026 20:18:07 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/my-experience-building-my-first-token-and-having-it-exist-on-chain-10pi</link>
      <guid>https://dev.to/peter_okoh_/my-experience-building-my-first-token-and-having-it-exist-on-chain-10pi</guid>
      <description>&lt;p&gt;There’s something quietly satisfying about seeing a token you built from scratch exist on-chain.&lt;/p&gt;

&lt;p&gt;Not just a random mint address…&lt;br&gt;
But a token with its own name, symbol, metadata, supply, and even transfers between wallets.&lt;/p&gt;

&lt;p&gt;Today made Solana feel a lot more real to me.&lt;/p&gt;

&lt;p&gt;What fascinates me most is how blockchain simplifies things that would normally require a full backend system in Web2.&lt;/p&gt;

&lt;p&gt;In a traditional app, you would create database tables for balances, build APIs for transfers, manage metadata, and maintain servers to keep everything running.&lt;/p&gt;

&lt;p&gt;But on Solana, the protocol already provides the structure.&lt;/p&gt;

&lt;p&gt;The mint becomes the definition of the currency.&lt;br&gt;
The associated token account becomes the balance record.&lt;br&gt;
And the transfer instruction becomes the movement of value between users.&lt;/p&gt;

&lt;p&gt;Except this time, everything is transparent and verifiable on-chain.&lt;/p&gt;

&lt;p&gt;I also explored Token Extensions metadata today, and I love the idea of storing metadata directly inside the mint account itself. Fewer moving parts, fewer accounts, lower costs, and a cleaner design overall.&lt;/p&gt;

&lt;p&gt;Still learning.&lt;br&gt;
Still experimenting.&lt;br&gt;
But moments like this make me genuinely excited for what’s ahead in the Solana ecosystem.&lt;/p&gt;

&lt;h1&gt;
  
  
  Day30
&lt;/h1&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%2Fud01wbaa8wd4zdx2y7zj.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%2Fud01wbaa8wd4zdx2y7zj.png" alt=" " width="800" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>solana</category>
    </item>
    <item>
      <title>#100DaysOfSolana Day29: My Experience Generating Token On Solana Devnet</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Wed, 20 May 2026 14:12:25 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/100daysofsolana-day29-my-experience-generating-token-on-solana-devnet-1j8g</link>
      <guid>https://dev.to/peter_okoh_/100daysofsolana-day29-my-experience-generating-token-on-solana-devnet-1j8g</guid>
      <description>&lt;p&gt;Yesterday felt different.&lt;/p&gt;

&lt;p&gt;I just created my first token on Solana Devnet using the SPL Token Program… and I can’t fully explain the excitement that came with seeing it live on-chain.&lt;/p&gt;

&lt;p&gt;Not a fake database entry.&lt;br&gt;
Not something sitting quietly in a backend server.&lt;/p&gt;

&lt;p&gt;An actual token hosted on the blockchain that anyone can verify.&lt;/p&gt;

&lt;p&gt;One thing that really stood out to me is how much Solana abstracts away the hard parts. In Web2, building something like this would mean creating database schemas, APIs, handling double-spending logic, server maintenance, and a lot more stress.&lt;/p&gt;

&lt;p&gt;But here?&lt;br&gt;
The SPL Token Program already provides a secure and audited foundation to build on.&lt;/p&gt;

&lt;p&gt;I also started understanding the structure behind it all:&lt;br&gt;
• The Mint account acts as the source of truth for the token&lt;br&gt;
• The Token account stores individual balances&lt;br&gt;
• And every wallet needs its own token account before receiving tokens&lt;/p&gt;

&lt;p&gt;At first, it felt unusual.&lt;br&gt;
Now, it’s starting to make sense.&lt;/p&gt;

&lt;p&gt;This may look like a small step, but for me, it feels like the beginning of something much bigger.&lt;/p&gt;

&lt;p&gt;Excited to keep building, keep breaking things, and keep learning deeper layers of Solana.&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%2Fbwijwd1bdjxijfpw4lxo.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%2Fbwijwd1bdjxijfpw4lxo.png" alt=" " width="799" height="166"&gt;&lt;/a&gt;&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%2Fh8ygdkhpnauc454wud3z.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%2Fh8ygdkhpnauc454wud3z.png" alt=" " width="800" height="62"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>solana</category>
      <category>100daysofsolana</category>
    </item>
    <item>
      <title>WEEK 4 #100DaysOfSolana: LAMPORTS IN SOLANA</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Wed, 20 May 2026 07:07:19 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/week-4-100daysofsolana-lamports-in-solana-2mb1</link>
      <guid>https://dev.to/peter_okoh_/week-4-100daysofsolana-lamports-in-solana-2mb1</guid>
      <description>&lt;p&gt;When I first started digging into Solana accounts, those fields,&lt;code&gt;lamports&lt;/code&gt;, &lt;code&gt;owner&lt;/code&gt;, &lt;code&gt;data&lt;/code&gt;, &lt;code&gt;executable&lt;/code&gt;,looked like low-level noise.&lt;/p&gt;

&lt;p&gt;But they’re actually the real “anatomy” of everything on-chain.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lamports&lt;/code&gt; is simply the balance of an account. Not abstract value, actual rent-paying power that keeps the account alive on the network.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;owner&lt;/code&gt; tells you "who controls the rules." It’s not about possession, it’s about which program has the authority to read, write, and mutate that account’s state.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;data&lt;/code&gt; is where the real story lives. It’s the storage layer—custom bytes that programs interpret however they were designed to. Same field, different meaning depending on the program behind it.&lt;/p&gt;

&lt;p&gt;And then there’s &lt;code&gt;executable&lt;/code&gt;. This one flips the perspective: is this account just data, or is it a program that can actually run instructions?&lt;/p&gt;

&lt;p&gt;Once these clicked for me, Solana stopped feeling like “magic transactions” and started looking like a structured system where every account has a job.&lt;/p&gt;

&lt;p&gt;And honestly, that shift changes everything.&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%2F2mcsul6q7wr5q9krt83h.webp" 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%2F2mcsul6q7wr5q9krt83h.webp" alt=" " width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>webdev</category>
      <category>100daysofsolana</category>
      <category>solana</category>
    </item>
    <item>
      <title>Week 4 #100DaysOfSolana: My Explorer</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Mon, 18 May 2026 11:27:33 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/week-4-100daysofsolana-my-explorer-fah</link>
      <guid>https://dev.to/peter_okoh_/week-4-100daysofsolana-my-explorer-fah</guid>
      <description>&lt;p&gt;Spent some time today exploring transaction history on Solana Explorer, and it’s honestly one of the easiest ways to understand what’s happening under the hood on-chain.&lt;/p&gt;

&lt;p&gt;In this screenshot, I’m looking at the transaction history of a Solana account on devnet. You can see successful and failed transactions, block numbers, timestamps, and raw transaction data all in one place. Seeing both successful and failed transactions side-by-side makes debugging feel much more practical.&lt;/p&gt;

&lt;p&gt;One thing that stood out to me was how transparent Solana transactions are. I didn’t realise how much detail the explorer exposes, from programme ownership down to transaction-level history and execution results. It really helps connect the theory of “everything is an account” to what’s actually happening on-chain.&lt;/p&gt;

&lt;p&gt;I used the Solana Explorer for this, and I’d definitely recommend it, especially for beginners learning how accounts, programs, and transactions interact. It makes the network feel far less abstract.&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%2Fsylr4zy84rtbzfwiiy1o.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%2Fsylr4zy84rtbzfwiiy1o.png" alt=" " width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  100daysofsolana
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Day28
&lt;/h1&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>100daysofsolana</category>
    </item>
    <item>
      <title>Week 4: #100DaysOfSolana; Account Model</title>
      <dc:creator>Peter Okoh</dc:creator>
      <pubDate>Mon, 18 May 2026 10:34:22 +0000</pubDate>
      <link>https://dev.to/peter_okoh_/week-4-100daysofsolana-account-model-5326</link>
      <guid>https://dev.to/peter_okoh_/week-4-100daysofsolana-account-model-5326</guid>
      <description>&lt;p&gt;On Solana, everything is an account. There’s no separation between wallet accounts, smart contracts, or data storage. They all live in one unified system. Every account is just a key-value entry where the key is a 32-byte address and the value is the account itself. I like to think of it as a giant filesystem where every file is an account.&lt;/p&gt;

&lt;p&gt;Every Solana account also shares the same structure. It always has five fields: lamports (the balance in SOL, where 1 SOL = 1 billion lamports), data (a raw byte array for storing state), owner (the program that controls the account), executable (a flag that tells you if it’s a program), and rent epoch (mostly deprecated and usually maxed out now).&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%2Ffc5o0lprbm634y9k9ytn.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%2Ffc5o0lprbm634y9k9ytn.png" alt=" " width="800" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The ownership rule is also very strict but simple. Only the owner program can modify an account’s data or deduct its lamports. However, anyone can send lamports into an account as long as it’s writable. This makes the security model very predictable because control is tied to ownership, not identity.&lt;/p&gt;

&lt;p&gt;One of the biggest surprises for me was that programs don’t store their own state. On Solana, programs are completely stateless. The program is just logic, while state lives in separate data accounts. So instead of a smart contract holding everything internally, it behaves more like a backend server that reads and writes to a database.&lt;/p&gt;

&lt;p&gt;Another important concept is rent exemption. Every account must hold a minimum amount of lamports based on its data size to stay alive on-chain. If it meets that threshold, it becomes “rent-exempt” and won’t be deleted. This can be gotten using:&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%2Ffu1cgiaqt5358bmfifj9.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%2Ffu1cgiaqt5358bmfifj9.png" alt=" " width="800" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make sense of it all, I like using a simple analogy: Solana is like a filesystem. Each account is a file with metadata (owner, permissions, size) and content (data). Programs are executable files, data accounts are documents, and the system program acts like the operating system that manages everything.&lt;/p&gt;

&lt;p&gt;Once this model clicks, Solana stops feeling abstract. Transactions start to look like structured file operations, and the entire system becomes much easier to reason about.&lt;/p&gt;

&lt;p&gt;Solana is making more sense to me now.&lt;/p&gt;

&lt;h1&gt;
  
  
  100DaysOfSolana
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Day27
&lt;/h1&gt;

</description>
      <category>100daysofsolana</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
  </channel>
</rss>
