DEV Community

Kingfaitho
Kingfaitho

Posted on

I Built a Solana Tip Jar

I’ll be honest. When I started this I had no idea what I was doing.
I knew some Solana basics. I’d read the docs, watched a few YouTube videos, nodded along like I understood everything. But actually building something? That was a different story.
So I set myself a challenge. Build a real dApp. Deploy it. Make it work. No tutorials holding my hand the whole way.
I chose a tip jar. Simple concept connect your wallet, enter an amount, send SOL to someone. How hard could it be?
Very hard as it turns out. But I got there.

Why a Tip Jar?
Because I wanted to build something real but not overwhelming.
A lot of beginner Solana tutorials have you building things that are either too simple to be impressive or too complex to actually finish. A tip jar sits right in the middle. It involves real wallet connections, real transactions, real money moving on a real blockchain. But the logic is simple enough that you can actually understand every line of code you write.
If you can’t explain what your code does you don’t really know it. That was my rule.

The Stack I Used

  1. Solana + Anchor for the smart contract
  2. React + Vite for the frontend
  3. Phantom wallet for connecting and signing
  4. Vercel for deployment I picked Vite over Create React App because honestly CRA feels ancient at this point. Vite is fast, modern and the developer experience is just better.

How the App Actually Works
When you open the app you see a Connect Wallet button. You click it, Phantom pops up, you approve the connection.
Now the app knows who you are your public key, your balance, everything it needs.
You type in how much SOL you want to send. You hit the button. Here is what happens behind the scenes in about 2 seconds:
The frontend builds a transaction. Think of a transaction like a signed cheque it says who is sending, who is receiving, how much, and your signature proving you authorized it.
That transaction goes to Solana devnet. Validators on the network check it, confirm it’s legitimate, and execute it. The SOL moves. The blockchain records it permanently.
Done. Nobody can reverse it. Nobody can lie about it. It just happened.
That permanence is what makes blockchain interesting to me. Not the hype, not the prices just the fact that code can enforce rules without anyone in the middle.

The Part That Almost Broke Me
Vite and Solana do not like each other out of the box.
Solana’s web3.js library was built when Webpack ruled everything. It relies on Node.js built ins like buffer that Vite deliberately excludes from browser bundles.
So I kept getting this error=
Module "buffer" has been externalized for browser compatibility

I stared at that error for longer than I want to admit.
The fix was actually two lines. Install the buffer package and add this to the top of main.tsx=
import { Buffer } from "buffer";
window.Buffer = Buffer;

Two lines. That’s it. Sometimes the most painful bugs have the most anticlimactic solutions.
What Anchor Actually Does
Before this project I thought Anchor was optional. Like a nice to have.
It is not optional. Writing a Solana program in pure Rust without Anchor is like building furniture with no tools technically possible but why would you do that to yourself.
Anchor handles all the boilerplate that would otherwise make you want to quit. Account validation, error handling, serialization it takes care of all of it so you can focus on what your program actually does.
My program does one thing. It takes SOL from one wallet and sends it to another. Here is the whole logic = pub fn send_tip(ctx: Context, amount: u64) -> Result<()> {
anchor_lang::system_program::transfer(
CpiContext::new(
ctx.accounts.system_program.to_account_info(),
anchor_lang::system_program::Transfer {
from: ctx.accounts.sender.to_account_info(),
to: ctx.accounts.receiver.to_account_info(),
},
),
amount,
)?;
msg!("Tip sent! 💰");
Ok(())
}

That CPI call at the end. Cross Program Invocation is basically my program saying “hey Solana’s System Program, please move this SOL for me.” Programs on Solana don’t move SOL directly. They ask the System Program to do it. Once that clicked everything made more sense.

Devnet vs Mainnet
Everything I built runs on devnet. Devnet is Solana’s testing environment same technology, same speed, but the SOL is fake and free.
This matters because mistakes on mainnet cost real money. On devnet you can break things, fix things, break them again, and it costs you nothing.
When I was ready to test I airdropped myself some devnet SOL = solana airdrop 2
Free money. Only on devnet. Enjoy it while you can.

Deploying It
I used Vercel and it took about 3 minutes.
Connect GitHub, import the repo, set the root directory to app, click deploy. That’s genuinely it. Vercel figured out it was a Vite project and handled the rest.
The app is live here: https://tip-jar-iota.vercel.app
The code is here: https://github.com/Kingfaitho/tip-jar

What I Would Do Differently
A few things I’d change if I started over:
Set up the buffer polyfill before writing any other code. Don’t discover that error halfway through like I did.
Use devnet from the very beginning and make sure Phantom is set to devnet before connecting. Mismatched networks cause confusing errors.
Write tests earlier. Anchor has a great testing setup with TypeScript. I skipped it to move fast and paid for it in debugging time.

What’s Next
This was version one. Here is what I want to add:
A transaction history so you can see every tip that was ever sent. A message field so senders can leave a note with their tip. Eventually a mainnet deployment when I’m confident enough to use real SOL.

If You’re Just Starting Out
Build something. Anything.
The docs are good. The tutorials are helpful. But nothing teaches you like staring at an error message at midnight and figuring it out anyway. Start small. Finish it. Deploy it. Then build the next thing.
That’s the whole strategy.

Top comments (0)