DEV Community

Cover image for I Spent My Time Building Tokens on Solana. What Got Me Surprised? Read This.
Murtala Mudi
Murtala Mudi

Posted on

I Spent My Time Building Tokens on Solana. What Got Me Surprised? Read This.

I want to tell you something nobody told me before I started this.

Building tokens on Solana is not complicated. The CLI does most of the heavy lifting. You run a few commands, something appears on-chain, and you can verify it in a block explorer within seconds. That part is genuinely smooth.

What is not smooth is the moment you realize how differently Solana thinks about money, ownership, and rules compared to everything you have built in Web2. That mental shift is where the real learning lives.

This is my honest account of building tokens on Solana for the first time, covering everything from a basic mint to soulbound credentials that cannot be transferred. I am a web developer still learning. These are my notes from the trenches.


Starting point: creating a basic token

The first thing I learned is that every token on Solana has two separate things: a mint and a token account.

The mint is the factory definition. It says: this token exists, it has 6 decimal places, and this wallet has authority to create more of it. The token account is where actual tokens live. Your wallet cannot hold tokens directly. It holds token accounts, one per token type, each one like a separate pocket.

Creating a token is one command:

spl-token create-token \
  --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \
  --enable-metadata \
  --decimals 6
Enter fullscreen mode Exit fullscreen mode

That --program-id flag points at the Token Extensions Program, also called Token-2022. It is the newer, more powerful version of Solana's original token program. I used it from day one because it supports features the original program cannot do.

After creating the mint I had to create a token account and then mint supply into it:

spl-token create-account [MINT_ADDRESS]
spl-token mint [MINT_ADDRESS] 1000
Enter fullscreen mode Exit fullscreen mode

Simple. But without metadata my token was just a random address. Nobody looking at it would know what it was.


The metadata moment

In Web2, if you launch an in-app currency you give it a name, a symbol, maybe a logo. You store that information in your database.

On Solana, with the Token Extensions Program, you can store metadata directly on the mint account itself. On-chain. No separate service, no external database.

spl-token initialize-metadata [MINT] "100DaysCoin" "HUNDO" "https://..."
Enter fullscreen mode Exit fullscreen mode

One command and my token had a name and symbol visible to any wallet, any explorer, any app that looked it up. That felt significant. The token's identity is part of the token, not hosted somewhere that could go down or change.


Transfer fees without a backend

This is the one that genuinely stopped me for a moment.

In Web2, if you want to take a cut of every transaction on your platform you build middleware. You intercept transfers, calculate the fee, route it to your account, handle edge cases, write tests for the fee logic, and pray nothing breaks when someone sends an unusual amount.

On Solana you configure it once at mint creation:

spl-token create-token \
  --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \
  --transfer-fee-basis-points 200 \
  --transfer-fee-maximum-fee 5000 \
  --enable-metadata \
  --decimals 9
Enter fullscreen mode Exit fullscreen mode

Two hundred basis points is 2%. From that point on, every transfer of this token automatically withholds 2% in the recipient's token account. Not in my account. Withheld in theirs, but locked so only I can collect it.

When I transferred 100 tokens to a second wallet the recipient got 98. The other 2 sat withheld. Then I ran one command to collect them:

spl-token withdraw-withheld-tokens [MY_TOKEN_ACCOUNT] [RECIPIENT_TOKEN_ACCOUNT]
Enter fullscreen mode Exit fullscreen mode

No backend. No payment processor. No middleware. The Token Extensions Program enforced the fee at the protocol level on every single transfer. I cannot think of an equivalent in Web2 that does not involve significant infrastructure.


The experiment I enjoyed most: making a token that cannot move

The last thing I built this week was a non-transferable token. The blockchain world calls these soulbound tokens.

spl-token create-token \
  --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \
  --enable-non-transferable
Enter fullscreen mode Exit fullscreen mode

I minted 10 tokens to my wallet then deliberately tried to send 5 to another wallet. The transaction failed:

Error: Non-transferable token
Enter fullscreen mode Exit fullscreen mode

That error was the point. The Token Extensions Program rejected the transfer at the protocol level. Not an application rule that a clever developer could bypass. The program itself will not process the instruction.

What I found interesting is that burning still works. The holder can destroy their own tokens. They just cannot give them to anyone else. So it is not about trapping someone with something they do not want. It is about making credentials that prove something about a specific wallet.

Think about course completion certificates. Currently these live in databases that companies control. On Solana a non-transferable token could represent that certificate permanently, tied to the wallet that earned it, verifiable by anyone, controlled by nobody.


What actually surprised me

The thing that surprised me most was not a feature. It was a constraint.

Extensions must be added at mint creation. You cannot add a transfer fee to an existing token. You cannot make a transferable token non-transferable after the fact. The configuration is baked in permanently.

Coming from Web2 where you can alter a database schema or deploy a new version of an API this feels restrictive. But it is also what makes these tokens trustworthy. When someone receives a token with a 2% transfer fee they know that fee will always be 2%. Nobody can change the rules after the fact. The immutability is the feature.

That is the mental shift Solana keeps asking you to make. What feels like a limitation is often a design decision that creates trust without requiring anyone to trust a specific person or company.


Where I am headed

I have been doing the #100DaysOfSolana challenge with Major League Hacking. I am five weeks in. Next up is moving beyond tokens into actual programs and on-chain logic.

If you are a Web2 developer curious about Solana my honest advice is this: do not wait until you understand the theory. Build something small, watch it work, watch it fail, and let the confusion lead you to the understanding. The concepts will click faster through a terminal than through documentation.

See you in the next post.

100DaysOfSolana #Solana #buildinpublic

Top comments (0)