Reflection

What Building a Web3 Gaming Platform Taught Me About Blockchain, Trust, and Real Money

Reflections on building a production Web3 gaming and NFT marketplace - the blockchain consistency problems nobody warns you about, why mainstream UX and crypto are harder to reconcile than it looks, and how designing real economic guarantees on-chain changes how you think about software.

Yodhimas Geffananda
Yodhimas Geffananda
Software Engineer
May 15, 2025
8 min read
What Building a Web3 Gaming Platform Taught Me About Blockchain, Trust, and Real Money

What Building a Web3 Gaming Platform Taught Me About Blockchain, Trust, and Real Money

There is a version of Web3 development that is mostly theoretical. You deploy a contract to a testnet, interact with it through a local frontend, and call it done. Everything works because nothing is real - no real users, no real money, no real consequences if the state gets corrupted.

Then there is the version where NFTs carry a buyback guarantee, where players earn in-game currency that can be withdrawn to a real bank account, and where a bug in your blockchain sync logic means someone cannot sell an asset they legitimately own.

I spent the better part of a year in the second version. Here is what it actually taught me.

The Blockchain Is Not Your Database

The single most important insight from this project: the blockchain and your database are two separate systems that will eventually disagree, and you need to decide in advance whose version of truth wins.

Early in the build, we had an asset listing system where the database stored a listed flag for each NFT. When a user listed an item, we updated the flag. When they viewed the marketplace, we queried the flag. Clean and simple.

The problem surfaced when a listing transaction failed on-chain but the database had already been updated. From the user's perspective, their item was listed. From the blockchain's perspective, it was not. When another user tried to buy it, the transaction reverted. No sale happened. But the seller had no idea why their item was "listed but unsellable."

The fix was conceptually simple but required rethinking the data model: the blockchain is always the source of truth, the database is always the cache. The listed flag in the database is only written after on-chain confirmation. Every read that matters resolves against the contract state, not the database copy.

This sounds obvious in retrospect. But when you are building fast and optimistic, it is easy to treat your database as the authority and the blockchain as a side effect. That inversion is where subtle bugs live.

Designing Economic Guarantees Is a Different Problem Than Designing Features

Most software features can be iterated on after launch. Pricing can change. UI can be redesigned. APIs can be versioned. The blast radius of a mistake is usually bounded - you ship a fix, users get the update, life continues.

Economic guarantees are different. When your platform commits that a certain class of asset has a minimum repurchase floor that grows with each resale, that commitment exists outside the codebase. It lives in the user's mental model of what they bought. Getting it wrong - even in a subtle way, like commingling two pools of funds that should be separate - is not a bug you patch. It is a broken promise.

Working through the payment architecture for this project forced a discipline I had not had to apply before: model the economic rules explicitly before writing a single line of code. Not in a product spec document that lives in a folder no one reads. In a domain model where every transfer of value has a named source, a named destination, and a clear reason.

The distinction between the platform's operating account and the player currency escrow pool, for instance, is invisible to the end user. They do not know it exists. But it has to exist as a first-class concept in the system, because if it does not, the numbers will eventually not add up - and in a financial system, numbers that do not add up are not a bug report. They are a liability.

Mainstream UX and Self-Custody Are Genuinely in Tension

A recurring challenge in building for Web3 is that the audience you most want to reach - people who have never thought about private keys - is the audience that blockchain UX is least designed for.

The solution we landed on was giving every user a custodial wallet by default, generated and encrypted on their behalf at signup. From the user's perspective: they created an account, like any other app. From the backend's perspective: they now have an Ethereum address, an encrypted private key in the database, and a wallet they can interact with through the platform without ever knowing what a seed phrase is.

This works well for onboarding. But it creates a tension that does not have a clean resolution: when you hold encrypted keys on behalf of users, you are a custodian in the legal and moral sense. You have accepted a responsibility that self-custody wallets specifically exist to avoid.

The right answer is not to pretend that tension does not exist. It is to take it seriously - key encryption that is actually strong, export paths so users can eventually take self-custody, OTP guards on sensitive operations - and to be honest that the convenience of custodial onboarding comes with tradeoffs.

The more interesting version of this problem is what happens when users graduate. A player who starts on the platform as a casual gamer might, a year later, want to move their assets to their own wallet and trade on external marketplaces. The system needs to support that exit gracefully, not trap value in a walled garden.

On-Chain Fee Splits Are Simpler Than You Think, Until They Are Not

When a sale happens on a blockchain marketplace, the naive mental model is: buyer pays, seller receives. In practice, even a modest fee structure - platform fee, creator royalty, buyback fund contribution - means every sale involves four or five simultaneous value movements.

There are two architectural approaches to this. You can do it all on-chain, in the contract, atomically: one transaction splits the USDC four ways and distributes it immediately. Or you can accumulate balances in the contract and settle them in a separate step, batch-style, off-chain.

We chose the second. The reasons were practical - gas efficiency, payout flexibility for artists who want bank transfers rather than crypto, accounting visibility before funds move - but the real lesson was about where complexity lives.

The on-chain split approach looks clean. One transaction, one event log, everything settled. But the moment an artist wants their royalties paid to a Wise account in euros, "everything on-chain" breaks down. The blockchain does not know what Wise is. So you end up building an off-chain layer anyway, just one that is awkwardly attached to on-chain events.

The complexity does not disappear when you put something on a blockchain. It relocates. Moving from on-chain splits to an internal ledger model did not reduce the complexity of the fee accounting. It moved it to a place where we could actually manage it with the tools we already had.

Immutability Changes How You Think About Getting It Right

In traditional software, there is a implicit safety net: if you get something wrong, you deploy a fix. Migrations, patches, version updates - the system is always changeable.

Smart contracts are not. Once deployed to mainnet, the code is what it is. You can deploy a new contract and migrate to it, but the original contract keeps existing, keeps being callable, keeps having the state it has. Users who interacted with version one are still interacting with version one unless you give them a reason to upgrade.

This fact changes how you approach decisions during development. It raises the cost of being wrong. It makes you spend more time on scenarios that feel unlikely, because on-chain, an unlikely scenario that you did not handle is not a future bug ticket - it is a permanent gap in the contract's logic.

I found this constraint clarifying, not paralyzing. When you know a decision cannot easily be undone, you make it more carefully. You think through the edge cases. You model the failure modes. In a counterintuitive way, the immutability of contracts made the design conversations more rigorous than they would have been in a system where we could always patch it later.

What Actually Matters in a Web3 Product

After building all of it - the contracts, the API, the marketplace, the payment rails, the admin tooling - the thing that strikes me most is how little of the interesting work was specifically blockchain work.

The blockchain layer is narrow. Two contracts. A handful of functions. Events that the backend listens to. The rest - the economic modeling, the user trust architecture, the payment reconciliation, the multi-persona UX design - is just software, applied to a problem domain that happens to include a distributed ledger as one of its components.

The projects that treat blockchain as the feature tend to build products that only blockchain enthusiasts want to use. The more interesting path is treating the blockchain as infrastructure - one component in a system whose actual value comes from the economics and experiences built on top of it.

That is what I tried to build here. Whether it worked is a question for the users, not the code.

0 views
Yodhimas Geffananda

Written by Yodhimas Geffananda

Software Engineer passionate about building web applications and sharing knowledge with the developer community.

Comments

Connect wallet to comment

No comments yet. Be the first!