Multiple Dev.to posts describe a learning-by-building effort on Solana devnet focused on Token-2022 (the “Token Extensions” program). Authors report creating fungible tokens from scratch using the Solana CLI, then adding on-chain metadata, minting supply, creating token accounts, transferring tokens between wallets, and verifying balances on Solana Explorer. Across the series, several Token-2022 extensions are emphasized as ways to move token rules into the protocol layer: transfer fees that withhold amounts during transfers; non-transferable (soulbound) mints that block transfers at the token-program level; and revocable credentials achieved by combining non-transferable tokens with a permanent delegate that can burn tokens without the holder’s consent. One author also describes building an NFT without Metaplex by configuring a mint as a 1-of-1 token with zero decimals, disabling mint authority, attaching Token-2022 metadata, and optionally using group/member extensions to model collections. Others stress that extension configuration and instruction order matter at mint creation time, and that many behaviors can be inspected directly by auditing on-chain account and extension data.
Builders document Solana Token-2022 use for tokens, soulbound credentials, and NFTs on devnet
Multiple Dev.to posts describe a learning-by-building effort on Solana devnet focused on Token-2022 (the “Token Extensions” program). Authors report creating fungible tokens from scratch using the Sol...
- Developers create and configure tokens on Solana devnet using the Token-2022 (Token Extensions) program and SPL Token CLI commands.
- Token-2022 supports on-chain token metadata, reducing reliance on separate metadata programs for basic NFT-like identity fields.
- Transfer-fee and non-transferable (soulbound) behaviors are enforced by the token program, not by application/back-end checks.
- Non-transferable tokens reject transfers at simulation/transaction time, producing transfer-disabled errors when tested.
- Some NFTs are built as token mints configured for 1-of-1 supply and zero decimals, with optional group/member extensions for collections, verified via Solana Explorer.
Building on Solana can massively simplify your application logic once set up correctly. Solana’s Token Extensions Program streamlines development by providing native, customizable features directly at the protocol level. As the Solana documentation states, it "provides more features through extra instructions referred to as extensions." Let’s break down exactly what this means and how you can leverage it for compliance-gated assets. The Fundamentals: Mints, Authorities, and Minting Before diving into extensions, we need to align on three foundational terms: Mint Account: An account owned by the Solana SPL Token Program. It doesn’t hold tokens itself; instead, it acts as the global "source of truth" for a token's configuration (e.g., total supply, decimals). Mint Authority: The entity (wallet or program) with the power to increase the token supply by generating new units against the Mint Account. Think of it like a central bank or an issuing body. Minting: The actual process of generating new units of a token, which directly increases the total supply. When you initialize a token on Solana; for instance, using the Command Line Interface (CLI), you can pass specific "tags" or arguments. These tags tell the network, "Hey, I want to enable this specific feature for this token." That is exactly what Token Extensions are. Crucial Note: A token’s extensions must be defined at the moment of creation. Once the Mint Account is initialized, you cannot add or remove extensions. Key Extensions for Compliance and Control While the Token Extensions Program supports a wide array of features; including native metadata configuration (like setting your token's name, symbol, and image asset), it shines brightest when used to enforce compliance. Here are four powerful extensions to know: 1. Non-Transferable Tokens This extension locks tokens to the account they are originally minted to, making them completely non-transferable between users. How it works: While they can't be traded, they can still be minted by the authority, burned (destroyed) by an authorized entity, or closed entirely once the balance hits zero. Use Cases: Non-transferable loyalty points, achievement badges, or identity-bound credentials. 2. Interest-Bearing Tokens This feature allows a mint to store an annualized interest rate directly on-chain. How it works: It’s important to note that this does not continuously inject new tokens into user accounts. The raw token balance stays the same. Instead, the UI amount adjusts over time to reflect the accumulated interest. Use Cases: Real-world assets (RWAs), bonds, or compounding financial instruments. 3. Immutable Owner By default, Solana allows a token account's ownership to be transferred to another wallet. The Immutable Owner extension permanently locks the account to its original owner. Why it matters: It prevents users from accidentally or maliciously bypassing transfer restrictions by simply trading the underlying wallet account structure. 4. Transfer Hooks & Permanent Delegates (Delegation) This acts as the ultimate gatekeeper for your token ecosystem. By establishing a permanent delegate or a transfer hook, the mint-level authority can enforce custom validation rules for every single transfer or burn. How it works: The authority retains the right to freeze, transfer, or burn tokens if a user violates platform policies. Use Cases: Regulated securities, compliance-gated enterprise tokens, or professional certifications that can be revoked if a holder breaks industry rules. Conclusion The Solana Token Extensions Program is an incredibly potent tool for developers. By baking common guardrails, compliance rules, and financial logic directly into the token mint itself, you eliminate the need to write complex, risky custom smart contracts. As I dive deeper into the Solana ecosystem, I’ll be sharing more architectural deep dives. Thanks for reading! What do you think? Are you building with Token Extensions? Which extension do you find most useful for your project? Let's discuss in the comments!
6 hours agoWhat I learned minting NFTs on Solana with Token Extensions Before this week, I thought creating a Solana NFT meant using a marketplace stack or relying on a separate metadata program. I wanted to understand what actually happens underneath. It turns out an NFT on Solana is still built from the same token primitives I had already been working with: a mint, a supply of one, zero decimals, and extensions that add meaning directly on-chain. This week I went from creating a basic 1-of-1 token to building a complete NFT with metadata, collections, and on-chain verification using Token Extensions. The mental model: what an NFT actually is on Solana The biggest shift was realizing that an NFT is not a completely different asset type. At the core, it is still a token mint. The difference is: Supply is exactly 1 Decimals are 0 Mint authority is disabled so no more copies can be created In Web2 terms, imagine creating a database row where the ID is unique, the quantity can never increase, and ownership history is tracked publicly. The first NFT I created started with a simple mint: solana config set --url https://api.devnet.solana.com spl-token create-token --decimals 0 spl-token create-account [YOUR_MINT_ADDRESS] spl-token mint [YOUR_MINT_ADDRESS] 1 spl-token authorize [YOUR_MINT_ADDRESS] mint --disable After this, the token was technically an NFT, but it had no identity. No name. No image. No metadata. It was just an on-chain asset waiting for more information. What I built: metadata, collections, and extensions The next step was adding identity. With Token Extensions, metadata can live directly with the mint account instead of depending on a separate metadata account. The metadata extension allowed me to attach: Name Symbol Image URI Attributes The flow looked like this: spl-token create-token \ --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \ --enable-metadata \ --decimals 0 spl-token initialize-metadata \ [YOUR_MINT_ADDRESS] \ "First Light" \ "LIGHT" \ [YOUR_METADATA_URI] Seeing the NFT appear in Solana Explorer with its own metadata was the moment it stopped feeling like a token experiment and started feeling like an actual NFT. The next challenge was collections. A real NFT usually belongs to something bigger. A collection is basically another mint that acts as the parent. The Group extension creates the collection: spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token \ --decimals 0 \ --enable-group Then member NFTs reference that group using the Member extension: spl-token initialize-member MEMBER_ONE_MINT COLLECTION_MINT Now the relationship exists fully on-chain: Collection → NFT members Similar to a database foreign key connecting two tables. The surprising part: what was different from Web2 Coming from Web2 development, I expected NFTs to be mostly application logic. A database stores metadata. A backend verifies ownership. A frontend renders the result. Solana flips a lot of that thinking. The blockchain itself becomes the source of truth. The mint account contains the structure. Extensions define additional capabilities. Explorer tools can directly read and display the data. I also found it interesting that metadata is not just a static image attached forever. The update authority can modify fields: spl-token update-metadata [MINT_ADDRESS] name "Field Notes" spl-token update-metadata [MINT_ADDRESS] rarity legendary spl-token update-metadata [MINT_ADDRESS] rarity --remove This felt very similar to updating a database record, except the change happens through a blockchain transaction. What I would build next After understanding the building blocks, the next step would be building an actual NFT application around them. Some ideas: A Flutter mobile app that creates and manages NFTs An NFT dashboard that reads extensions directly from Solana A creator platform where users mint collections without writing CLI commands AI-generated NFTs with dynamic metadata updates The biggest lesson from this week: NFTs are not magic objects. They are carefully designed token structures with rules, ownership, metadata, and relationships. Understanding the primitives makes the whole ecosystem easier to build on. This post is part of #100DaysOfSolana. Follow along or jump in any day. Beginner #DEV
3 days agoBefore this week I thought you needed Metaplex to build a real Solana NFT. It turns out you can mint a full NFT, stamp metadata directly onto it, group it inside a collection, audit every byte, and mutate it live — using only the Token Extensions program and the SPL token CLI. No third-party framework required. This post covers what I built during Days 44–47 of #100DaysOfSolana, what surprised me coming from a Web2 background, and what I would build next. The Mental Model: What a Solana NFT Actually Is Before writing a single command, I had to unlearn something. In Web2, an NFT feels like a record in a database that points to a JPEG. On Solana, it is simpler and more precise than that. A Solana NFT is just a mint account with three properties set just right: Property Value Supply 1 (exactly one token exists) Decimals 0 (cannot be split) Mint authority (not set) — disabled forever That is it. The "NFT-ness" is not a special program. It is a configuration of the same SPL Token primitives that power every fungible token on the network. What makes a modern Solana NFT different from a bare 1-of-1 token is the Token Extensions program (Token-2022). Instead of storing metadata in a separate account managed by Metaplex, Token Extensions lets you stamp the name, symbol, URI, and custom fields directly onto the mint account itself. Everything lives in one place. Any wallet, any marketplace, any RPC node can read it without trusting a third-party indexer. What I Built: Four Days, Four Commands Day 44 — First NFT with on-chain metadata I minted a 1-of-1 token using the Token-2022 program, initialized a Metadata Pointer extension on it, and attached a name, symbol, and URI pointing to a JSON file on GitHub Gist. # Create the mint with metadata extension enabled spl-token create-token \ --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \ --enable-metadata \ --decimals 0 \ ./nftTnVuyNU1kwTgv7edG6BPmHCtp2NMrawbw94kwZTF.json # Stamp name, symbol, and URI directly onto the mint spl-token initialize-metadata \ nftTnVuyNU1kwTgv7edG6BPmHCtp2NMrawbw94kwZTF \ "First Light" \ "LIGHT" \ "https://gist.githubusercontent.com/gopichandchalla16/..." Mint address: nftTnVuyNU1kwTgv7edG6BPmHCtp2NMrawbw94kwZTF View on Solana Explorer (devnet) Day 45 — NFT collection using Group and Member extensions I created a separate collection mint using the Group extension, then minted two member NFTs and registered each one under the collection using the Member extension. # Register a member NFT into the collection spl-token group-member-initialize \ <MEMBER_MINT> \ <COLLECTION_MINT> \ --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb The collection mint ended up with Size: 2, Max Size: 3. Each member NFT carries a Group field that points byte-for-byte to the collection mint — the on-chain equivalent of a foreign key. Day 46 — Auditing every byte on devnet Instead of trusting that everything worked, I read both mints back from devnet the same way a senior engineer reviews their own work before shipping. spl-token display nftTnVuyNU1kwTgv7edG6BPmHCtp2NMrawbw94kwZTF spl-token display AC3peC3tdZUnLY44zGYC7YAuEaPknkMcRqsmAyvXJtMx The key check was this line inside Token Group Member on each member NFT: Group: AC3peC3tdZUnLY44zGYC7YAuEaPknkMcRqsmAyvXJtMx ✅ That address matches the collection mint exactly. Phantom and every marketplace reads this field to verify collection membership — without trusting any off-chain index. That is what "verifiable provenance" actually means. Not marketing. Just two byte arrays comparing equal. Day 47 — Mutating metadata live This was the day I stopped treating the NFT like a fragile artifact and started treating it like a live row of data. # Rename it spl-token update-metadata nftTnVuy... name "Field Notes" # Add a custom field — the schema is completely open spl-token update-metadata nftTnVuy... rarity legendary # Remove it spl-token update-metadata nftTnVuy... rarity --remove # Swap the URI to point at a new metadata JSON spl-token update-metadata nftTnVuy... uri https://gist.githubusercontent.com/janvinsha/... Every command was one transaction. Every change appeared in Explorer within seconds. The Surprising Part Three things hit differently than I expected coming from Web2. 1. The on-chain layer and the off-chain layer move at different speeds. When I renamed the NFT to "Field Notes", Explorer showed the new name in seconds. But the image — which lives at the URI I pointed at, hosted on GitHub Gist — stayed cached in wallets for much longer. The on-chain pointer updates instantly. The thing it points at does not. This is why serious NFT projects use Arweave or IPFS for permanent image hosting instead of a mutable HTTP server. 2. There is no separate NFT program. I kept waiting to discover the "real" NFT layer. There is none. The same Token-2022 program that handles transfer fees, interest-bearing tokens, and compliance controls is also the program that handles NFT metadata and collections. Extensions compose on the same primitives. 3. The metadata schema is a blank canvas. The additional_metadata array accepts any key-value pair you want. I stamped rarity: legendary onto a live mint in one CLI call and watched it appear on Explorer. No migrations. No schema definitions. No contract upgrades. Just one transaction. What I Would Build Next Permanent image hosting — move the image URI from GitHub Gist to Arweave so the pointer and the asset are both permanent Dynamic NFT — use the mutable metadata to track something that changes over time, like XP or level in a game (Solana's official Dynamic Metadata NFT guide covers this pattern) Metaplex comparison — Metaplex Core is the dominant alternative NFT standard on Solana, with a different account structure and royalty model. I want to build the same collection in both standards and write a direct comparison. Resources I Actually Used Token Extensions overview — the canonical reference Metadata Pointer and Token Metadata — how metadata lives on the mint Token Groups and Members — how collection membership works Dynamic Metadata NFTs guide — the official Solana guide for what comes next Solana Explorer (devnet) — for verifying every change live All the code and terminal output from every day is in my public repo: 👉 github.com/gopichandchalla16/100-days-of-solana This post is part of #100DaysOfSolana. Follow along or jump in any day at mlh.link/solana-100.
1 week agoBefore this week, NFTs on Solana weren't new to me. I've previously worked with Programmable NFTs (pNFTs) and even built projects that integrate them. However, most of my experience was centered around the Metaplex ecosystem, so I tended to think about NFTs through that lens. What surprised me during this learning arc was discovering how much can be built directly with Token Extensions. By creating NFTs from the token level upward, I gained a much deeper understanding of the underlying primitives that make digital assets work on Solana. The Mental Model: What Is an NFT on Solana? As developers, we often interact with NFTs through SDKs, frameworks, and marketplace tooling. Those abstractions are useful, but they can hide what's actually happening on-chain. This week helped me simplify the model: An *NFT * is fundamentally a token mint configured with: A supply of one Zero decimals Metadata describing the asset Optional relationships to collections or groups Using Token Extensions, many of these capabilities can be attached directly to the token itself rather than relying on additional programs or infrastructure. That shift in perspective was one of the biggest takeaways from this challenge. What I Built Over the course of this arc, I created an NFT on Solana Devnet using Token Extensions and explored several capabilities that I had never implemented directly before. The process included: Creating a mint configured as an NFT Adding metadata using the Metadata Extension Minting a single token Creating a collection using the Group Extension Associating the NFT with the collection through the Member Extension Auditing the account structure and extension data on-chain Updating metadata after the NFT had already been created One of the most valuable parts of the exercise was inspecting the accounts directly instead of relying solely on SDK abstractions. For example: spl-token initialize-metadata \ <NFT_MINT> \ "My First NFT" \ "MNFT" \ https://example.com/metadata.json Seeing how the metadata is stored and referenced at the token level gave me a much clearer understanding of how Token Extensions work behind the scenes. The Surprising Part The most surprising discovery was how self-contained the Token Extensions approach feels. Coming from pNFT development, I was already familiar with advanced NFT functionality. What I didn't fully appreciate was how many NFT features can now be represented directly through token extensions. The Group and Member Extensions were especially interesting because they model collection relationships as native on-chain structures rather than purely application-level concepts. Another surprise was how easy it became to inspect and verify everything. By auditing the mint accounts and extension data directly, I could see exactly how the NFT was composed and how each extension contributed to its behavior. That level of transparency made the architecture much easier to understand. What I Would Build Next Now that I've explored NFT construction with Token Extensions, I'd like to experiment with more dynamic asset models. Some ideas include: Achievement NFTs that evolve based on user actions On-chain certificates with updateable attributes Membership assets with configurable permissions Hybrid systems that combine Token Extensions with pNFT functionality Understanding both approaches gives developers more flexibility when deciding which NFT architecture best fits a particular use case. Even with previous experience building NFT applications on Solana, this challenge helped me understand the ecosystem at a deeper level. Instead of viewing NFTs only through higher-level frameworks, I now have a much clearer picture of the token primitives that power them. Token Extensions, Metadata, Group, and Member Extensions demonstrate that NFTs on **Solana **are more than collectibles. They're programmable digital assets built from composable on-chain components.
1 week agoThis is a submission for the GitHub Finish-Up-A-Thon Challenge What I Built Honestly, I almost didn't write this post. Not because I didn't have anything to show — but because I kept telling myself "it's not done yet." Sound familiar? Back in early 2026, I started a repo called 100 Days of Solana. The idea was simple: learn Solana development from absolute zero, build something on-chain every single day, and document it publicly. Day 1, I generated a keypair. That was it. One file in the repo — a README with a title and no code. I had no blockchain background, only a Web2 history in Python and JavaScript. I didn't even know what "rent" meant in the context of Solana accounts. But I kept showing up. 44 days later, here's what that same repo became: ✅ Wallets, airdrops, SOL transfers, SPL token creation ✅ Token-2022 extensions — transfer fees, interest-bearing tokens, default frozen, non-transferable (soulbound), permanent delegate ✅ A fully named, on-chain NFT — "First Light" — with metadata, image, and permanently locked supply. Minted using only the Solana CLI. No Metaplex. No framework. ✅ 9 published DEV.to articles translating every concept into Web2-friendly language ✅ Every single transaction signature linked to Solana Explorer so you can verify my work on-chain This project means more to me than any side project I've ever started. It's proof that 30 minutes a day, compounded over 44 days, produces something real and verifiable. And GitHub Copilot is a big reason I didn't quit on Day 8, Day 23, or Day 39. 🔗 Repo: https://github.com/gopichandchalla16/100-days-of-solana Demo 🌐 "First Light" — My First NFT, Live on Solana Devnet I built this NFT end-to-end using nothing but spl-token CLI commands. No framework. No JS. Just me, the terminal, and a lot of patience. Field Value Name First Light Symbol LIGHT Mint Address nftTnVuyNU1kwTgv7edG6BPmHCtp2NMrawbw94kwZTF Program Token-2022 Supply 1 (locked forever) Decimals 0 Extensions metadataPointer + tokenMetadata Mint Authority Disabled 🔒 🔗 View "First Light" on Solana Explorer The vanity keypair starting with nft took about 20 minutes to generate locally using solana-keygen grind. Every character you see in that address was intentional. 📋 Every Step — Verified On-Chain Here are all 5 transactions, in order. You can click any of them and see exactly what happened on the Solana blockchain: Step What I Did Verified Transaction 1 Created mint account, initialized metadata pointer, initialized mint 3iXwa…jzXtz 2 Initialized token metadata — name, symbol, URI 45PYG…Kv2D4 3 Created the associated token account gWLGo…Ymmgj 4 Minted exactly 1 token 3B8MS…wrQoP 5 Revoked mint authority — forever 3Yhop…kckqo No one can ever mint another LIGHT token. That is by design. 📰 9 Published DEV.to Articles (300+ total reactions) These are not just summaries of what I did. Each one is a full explanation written specifically for Web2 developers entering the Solana ecosystem: Your Public Key Is Your Identity — What Web2 Devs Need to Know About Solana Solana Transactions Explained for Backend Developers (With Real Failures) I Built 5 Token Extension Combinations on Solana This Week — Here's What Each One Does 📊 Where the Project Stands Metric Status 🟣 Daily Build Progress 44 / 100 Days Complete 🖤 DEV.to Articles 9 Published 🟢 On-Chain Transactions Live on Solana Devnet 📄 License MIT 🔒 NFT Mint Authority Disabled Forever The Comeback Story Let me be honest about where this project started and where it almost ended. Day 1 — What the repo actually looked like gopichandchalla16/100-days-of-solana └── README.md ← literally just a title That was it. I had written "100 Days of Solana — learning in public" and committed it at midnight. No code. No plan. Just a title and the pressure of having put it on GitHub. The first week was rough. The Solana docs are not beginner-friendly if you're coming from Web2. The Token-2022 documentation is especially sparse. I spent 3 hours on Day 4 just trying to understand why my airdrop wasn't showing up (I was checking the wrong cluster). There were three moments where I almost stopped entirely: Day 8 — I couldn't figure out why my token transfer kept failing with a cryptic 0x1 error. I had been at it for two hours and it was past midnight. I nearly closed the laptop and told myself I'd "come back to it." Day 23 — I hit a wall with Token-2022 extension architecture. I understood how individual extensions worked but not how to compose them safely. Nothing I read explained it in plain terms. Day 39 — The NFT build broke on step 2 of 5. My metadata wasn't being initialized because I ran initialize-mint before initialize-metadata-pointer. The error wasn't obvious. I almost started over from scratch. I didn't quit any of those nights. GitHub Copilot helped me through each one — and I'll explain exactly how in the Copilot section. Day 44 — What the repo became gopichandchalla16/100-days-of-solana ├── day-01/ through day-44/ ← 44 documented daily builds ├── 9 DEV.to articles published ├── Every tx signature verified on Solana Explorer ├── Token-2022 extensions built and tested: │ ├── Transfer fees (compliance use case) │ ├── Interest-bearing tokens (DeFi use case) │ ├── Default frozen + thaw (regulated assets) │ ├── Non-transferable / soulbound (credentials) │ └── Permanent delegate (revocable access) ├── NFT "First Light" — vanity keypair, Token-2022, │ on-chain metadata, locked supply └── README with live progress bar, week logs, all explorer links The difference between Day 1 and Day 44 is not just the code. It's the understanding behind it. The 3 moments that defined this project Day 13 — The account model finally made sense. I had been running solana balance and spl-token create-account for days without really understanding why Solana accounts need rent. Then I sat down and wrote a DEV.to article explaining it with a Web2 analogy: accounts are like database rows, rent is like a monthly hosting fee — stop paying and the row gets deleted. Writing that article forced me to understand it deeply enough to explain it simply. After Day 13, I stopped copying commands and started understanding what each one actually does. Days 36–40 — Five Token-2022 extension combinations in one week. This was the hardest week. I built: A transfer fee token (simulating a transaction tax) An interest-bearing token (simulating a yield-bearing asset) A default-frozen token with thaw authority (compliance gating) A non-transferable soulbound token (on-chain credential) A permanent delegate token (revocable programmatic access) Each one is a real devnet transaction. Each one has a verifiable signature on Solana Explorer. Each one taught me something different about how Token-2022 is designed to handle real-world financial and compliance scenarios. Days 43–44 — My first NFT. No Metaplex. Just the CLI. I wanted to understand NFTs at the protocol level — not through a framework, not through a library, but through raw spl-token commands. I generated a vanity keypair starting with nft using solana-keygen grind. I added two Token-2022 extensions: metadataPointer and tokenMetadata. I minted exactly 1 token. I disabled the mint authority forever. "First Light" now lives on-chain permanently with its name, symbol, and metadata URI intact. Nobody can create another one. That's what makes it an NFT. The biggest technical lesson of 44 days Token-2022 extensions cannot be added after mint creation. Ever. There's no workaround. No patch. No update instruction. You must decide your full extension set before you run initialize-mint. It's like designing a database schema — you can't add a non-nullable column without a migration. I learned this the hard way on Day 38 when I tried to add interest-bearing to an existing mint. The transaction failed and I had to start the token from scratch. That 30-minute mistake became the most important architectural lesson I've had in 44 days. My Experience with GitHub Copilot I want to be specific here, not just say "Copilot helped a lot." Here are the exact moments where it made the difference. When I was stuck on 0x11 at midnight (Day 37) My compliance-gated token transfer failed with error 0x11 — AccountFrozen. I knew the token was frozen by design but I thought I had thawed it. The transaction kept failing anyway. I was staring at the error in my terminal. Copilot's inline suggestion explained what I was missing: both the sender's ATA and the recipient's ATA need to be thawed — not just the sender's. One suggestion. One minute. Problem solved. Without Copilot, I would have been digging through the SPL Token source code for the next hour — or worse, I would have given up and moved on without truly understanding the error. When soulbound tokens confused me (Day 40) Non-transferable tokens are conceptually simple — once minted to a wallet, they can never move. But when I tried to demonstrate this by attempting a transfer, the transaction failed with 0x25. I didn't expect the error. Copilot explained: non-transferable tokens can be burned but not transferred. It then suggested I write a burn script to demonstrate the constraint properly — which turned into the best hands-on example in my Week 6 article. The bug became the feature. That happens a lot when Copilot is involved. Writing CLI commands faster and correctly The Token-2022 program ID is 44 characters long: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb Before Copilot, I copied this from docs and sometimes mis-pasted it. With Copilot, it autocompleted the entire ID, the --program-id flag, all the relevant options, and even the correct sequence of commands. The sequence matters enormously in Token-2022. For the NFT build, initialize-metadata-pointer must come before initialize-mint. The Solana docs don't emphasize this clearly for beginners. Copilot's autocomplete surfaced the correct order naturally, in context, while I was typing. That saved me from the exact error that had broken my build on Day 39. Turning raw terminal output into readable articles Every DEV.to article I wrote started the same way: a terminal window full of transaction signatures, error codes, and hex-encoded account data. Copilot helped me turn that raw output into: Clear Web2 analogies that explain Solana concepts without jargon A consistent structure: what I planned → what broke → what I learned Opening paragraphs that hook readers who have never touched blockchain Nine articles. 300+ reactions across all of them. That audience engagement would not exist without Copilot helping me bridge the gap between "developer notes" and "readable article." Explaining the "why" — not just the "how" This is the thing I appreciate most about Copilot, and it's hard to quantify. When a command worked, I often didn't fully understand why it worked. Copilot's inline comments filled those gaps constantly: "This flag enables close authority so you can reclaim rent later." "The metadata pointer must be initialized first because the mint instruction reads the extension list." "Revoking mint authority is a one-way operation — there's no re-enable instruction in Token-2022." These micro-explanations compounded over 44 days into real, deep understanding of the protocol. I'm not just writing Solana commands anymore. I understand what they do and why they exist. The honest summary GitHub Copilot didn't write this project for me. Every transaction on Solana Explorer is a decision I made, a command I typed, a concept I understood. But Copilot removed the friction that would have made me quit. It turned 2-hour debugging sessions into 10-minute ones. It turned terminal output into articles people actually read. It turned "I don't understand this" into "oh, that's why." 44 days in. 56 to go. I'm not stopping. 🔗 GitHub Repo: https://github.com/gopichandchalla16/100-days-of-solana 📰 DEV Profile: https://dev.to/gopichand_dev 🐦 X / Twitter: https://x.com/GopichandAI If you're a Web2 developer curious about Solana — follow the repo. Every day folder has the exact commands I ran, the errors I hit, and what I learned. It's all there. #100DaysOfSolana #Solana #Web3 #BuildInPublic
1 week agoI spent 7 days learning Solana token extensions. Here's what clicked, what surprised me, and the code you need to build tokens that can't be traded but can be revoked. The Problem (In Web2 Terms) Imagine you work in HR. You issue an employee a digital badge proving they're a certified security officer. Here's what you'd want: The badge stays in their wallet — they can't trade or sell it Only they can use it If they leave the company or fail a compliance check, you can revoke it silently without their permission The badge metadata (name, symbol, type) is on-chain and permanent You could build this with centralized databases and APIs. On Solana, it's just three extensions on a token mint. What Are Token Extensions? Solana's Token-2022 program lets you attach additional behaviors to any mint at creation time. Think of them like middleware for tokens. Before extensions, every token was the same — a mint with supply and decimals, token accounts holding balances, and transfer instructions. Extensions let you add rules on top: Extension What It Does Use Case Transfer Fee Charge a percentage on every transfer Protocol revenue, marketplace commissions Non-Transferable Make tokens unmovable after minting Soulbound badges, credentials, memberships Permanent Delegate Let the issuer burn tokens from anyone Revocable credentials, subscriptions with expiry Metadata Store name, symbol, URI on-chain Self-describing tokens, no external API needed Default Account State Freeze all new accounts by default Compliance gates, KYC verification The critical rule: extensions must be declared at mint creation. You cannot add them later. This forces you to think about your token's full lifecycle before deploying — which is good design discipline. The Journey: Three Combinations That Matter Over the past week I built three different token types. Here's what I learned from each. Day 34: Transfer Fees (The Marketplace Token) A token that charges 1% on every transfer, withheld automatically and sweepable by the issuer. What clicked: Fees are calculated at the protocol level — there's no fee handler to bypass. If someone transfers your token, the fee is withheld. Full stop. Day 37: Multi-Extension Token (The Compliance Token) I combined three extensions at once: TransferFeeConfig + InterestBearingConfig + MetadataPointer. What clicked: Extensions are truly independent. The interest-bearing display formula applies regardless of whether a fee is configured. The metadata doesn't affect functionality. They compose without interfering. Days 38–40: Soulbound Credentials (The Revocable Badge) The combination that unlocked a genuinely new primitive: NonTransferable — token can't move PermanentDelegate — issuer can revoke without the holder's consent MetadataPointer — credential is self-describing on-chain The Code: Building a Revocable Credential I'm on Windows without access to the spl-token CLI, so I built this entirely in Node.js using @solana/web3.js and @solana/spl-token. import { Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; import { ExtensionType, TOKEN_2022_PROGRAM_ID, createInitializeMintInstruction, createInitializeNonTransferableMintInstruction, createInitializePermanentDelegateInstruction, createInitializeMetadataPointerInstruction, getMintLen, getAssociatedTokenAddressSync, createAssociatedTokenAccountInstruction, mintTo, createBurnInstruction, } from "@solana/spl-token"; import { createInitializeInstruction, pack, TYPE_SIZE, LENGTH_SIZE } from "@solana/spl-token-metadata"; const connection = new Connection("https://api.devnet.solana.com", "confirmed"); // Load your saved keypairs (never generate fresh keypairs on every run) const authority = loadWallet("~/.config/solana/id.json"); // issuer const recipient = loadWallet("~/recipient-wallet.json"); // holder const mintKeypair = Keypair.generate(); // new mint each run const mint = mintKeypair.publicKey; // Define metadata const tokenMetadata = { mint, name: "Solana Dev Credential", symbol: "CRED", uri: "https://example.com/credential.json", additionalMetadata: [], }; // Calculate space: base mint + extensions + metadata const metadataExtLen = TYPE_SIZE + LENGTH_SIZE + pack(tokenMetadata).length; const extensions = [ ExtensionType.NonTransferable, ExtensionType.PermanentDelegate, ExtensionType.MetadataPointer, ]; const mintLen = getMintLen(extensions); const mintLamports = await connection.getMinimumBalanceForRentExemption( mintLen + metadataExtLen ); // Build the transaction — instruction order matters const createMintTx = new Transaction().add( // 1. Allocate the account SystemProgram.createAccount({ fromPubkey: authority.publicKey, newAccountPubkey: mint, space: mintLen, lamports: mintLamports, programId: TOKEN_2022_PROGRAM_ID, }), // 2. Extension initializers MUST come before createInitializeMintInstruction createInitializeNonTransferableMintInstruction(mint, TOKEN_2022_PROGRAM_ID), createInitializePermanentDelegateInstruction( mint, authority.publicKey, // issuing authority = permanent delegate TOKEN_2022_PROGRAM_ID ), createInitializeMetadataPointerInstruction( mint, authority.publicKey, mint, TOKEN_2022_PROGRAM_ID ), // 3. Initialize the mint itself (0 decimals — credentials are whole units) createInitializeMintInstruction( mint, 0, authority.publicKey, authority.publicKey, TOKEN_2022_PROGRAM_ID ), // 4. Write metadata on-chain createInitializeInstruction({ programId: TOKEN_2022_PROGRAM_ID, metadata: mint, updateAuthority: authority.publicKey, mint, mintAuthority: authority.publicKey, name: tokenMetadata.name, symbol: tokenMetadata.symbol, uri: tokenMetadata.uri, }) ); await sendAndConfirmTransaction( connection, createMintTx, [authority, mintKeypair] ); console.log("✅ Mint created:", mint.toBase58()); // Create recipient's token account (authority pays) const recipientATA = getAssociatedTokenAddressSync( mint, recipient.publicKey, false, TOKEN_2022_PROGRAM_ID ); const createATATx = new Transaction().add( createAssociatedTokenAccountInstruction( authority.publicKey, recipientATA, recipient.publicKey, mint, TOKEN_2022_PROGRAM_ID ) ); await sendAndConfirmTransaction(connection, createATATx, [authority]); // Mint 1 credential to the recipient await mintTo( connection, authority, mint, recipientATA, authority, BigInt(1), [], undefined, TOKEN_2022_PROGRAM_ID ); console.log("✅ Credential issued to recipient"); // === TRANSFER ATTEMPT — will fail === // (Try this yourself — the NonTransferable extension blocks it at simulation) // === REVOCATION — authority burns without holder's consent === const revokeTx = new Transaction().add( createBurnInstruction( recipientATA, mint, authority.publicKey, // permanent delegate signs — NOT the holder BigInt(1), [], TOKEN_2022_PROGRAM_ID ) ); await sendAndConfirmTransaction(connection, revokeTx, [authority]); console.log("✅ Credential revoked — recipient balance: 0"); What Surprised Me Silent revocation is real. I expected revoking to require the holder's signature. It doesn't. The permanent delegate burns the token without any interaction from the holder. For compliance scenarios, that's exactly what you want — but it's worth being deliberate about who you hand this power to. Transfer is blocked at simulation, before the chain. When I tried to transfer a NonTransferable token, the RPC rejected the transaction before it was even submitted. No gas spent, no on-chain footprint. The rejection is that clean. Instruction order is unforgiving. Extension initializers must run before createInitializeMintInstruction in the same transaction. Put them in the wrong order and you get a cryptic error. Once I understood that extensions configure the account before the mint is initialized, the order made sense. What Confused Me Token accounts vs. mints. For the first few days I kept conflating these. The mint holds supply, decimals, authorities, and extensions. A token account (ATA) is where a holder's balance lives. Extensions live on the mint. Token accounts just hold tokens and follow the mint's rules. Why so many instructions? Creating a mint with three extensions means six instructions in one transaction. The reason is modularity — you only pay for what you use. A basic mint is one instruction. A complex mint is six. Cost scales with your needs. What Clicked Extensions are middleware, not token types. I kept thinking of NonTransferable tokens as a different kind of token. They're not. It's the same token with a rule bolted on. Transfer fee is a rule. Permanent delegate is a rule. Rules compose. This unlocks genuinely new primitives. Before Token-2022 extensions, soulbound + revocable in a single token was not possible on Solana without a custom program. Now it's a 50-line script. That matters. The Real Gotchas Save your keypairs. Generate once, save to JSON, load on every run. Generating fresh keypairs every time means your authority has no SOL on the next run. // Save fs.writeFileSync("authority.json", JSON.stringify(Array.from(kp.secretKey))); // Load const kp = Keypair.fromSecretKey( Uint8Array.from(JSON.parse(fs.readFileSync("authority.json", "utf8"))) ); Always pass TOKEN_2022_PROGRAM_ID when working with Token-2022 mints. The default program ID in most helper functions points to the original SPL Token program. Pass the wrong one and your transactions fail with confusing errors. Base units, not whole tokens. Every numeric parameter is in base units. With 0 decimals this is fine — 1 base unit = 1 token. With 9 decimals, BigInt(1) = 0.000000001 tokens. Always scale by 10 ** decimals. How This Compares to Web2 Feature Web2 Solana Extensions Issue a credential API call, DB entry Mint a token with extensions Holder keeps it forever Require them to log in to see it Non-Transferable: it just lives in their wallet Revoke silently Flip a flag in your DB, holder doesn't know Permanent Delegate: authority burns it without consent Verify credential Call your API Query the chain for the token balance Cost Your servers, your infrastructure Minimal (rent-exempt account on Solana) The shift: you don't control the infrastructure. The token is self-custody. The rules are on-chain. The program enforces them, not your API. Going Deeper The official Token Extensions documentation covers every extension with parameters, use cases, and CLI examples. If you're following the 100 Days of Solana challenge, the extension challenges build on each other across several days — start with a basic mint, add metadata, add transfer fees, then combine everything. Extensions I haven't tried yet that look interesting: Interest-bearing — display a time-adjusted balance using continuous compounding, no new tokens minted Confidential transfers — encrypted token amounts on a public chain Oracle-driven freezes — freeze accounts based on external data The pattern is clear: token behavior is becoming a set of composable, declared rules. That's what programmable money looks like. Built on Solana devnet. All code written in Node.js on Windows — no CLI available, every challenge solved programmatically using @solana/web3.js and @solana/spl-token.
2 weeks ago
Funny memes shared across Nairobi as users post trending content
Multiple Nairobi Wire posts highlight humorous memes circulating among social media users in Nairobi over several days,...
Jensen Huang says society must adopt new social norms in the age of AI
Nvidia CEO Jensen Huang says society needs “new social norms” as artificial intelligence becomes widely used. In an Asso...
No story details provided in the supplied New York Times entries
I can’t synthesize or extract agreed-upon facts because the provided inputs contain only placeholder text (“Here’s the l...