# My First On-Chain Experience on Base **Published by:** [Mario](https://paragraph.com/@tortmario/) **Published on:** 2025-12-19 **Categories:** base mini app development, base l2 ethereum, farcaster mini app, on-chain off-chain architecture, next.js web3 application, erc-721 smart contract base, web3 mini app architecture, ethereum l2 rpc performance, smart contract deployment base **URL:** https://paragraph.com/@tortmario/my-first-on-chain-experience-on-base ## Content The Wall Base: Technical Architecture of a Social Mini App on Base App On December 18, 2025, Base officially launched its Mini App SDK, but I got access a bit earlier during the beta phase. That immediately raised a question for me: Can I build a mini app where every user action leaves an on-chain footprint, while still keeping a fast, Web2-like UX? That’s how The Wall Base was born — a social mini app running inside Farcaster / Base App. What is The Wall Base? The Wall Base consists of: a social feed of posts; NFT minting for each post; a marketplace tovery action; an off-chain raffle that pays the pool to a random NFT owner. This is my first experience with Base SDK and on-chain development, and in this article I share what I learned and what I struggled with. If you have suggestions on how something could be done better or simpler — feel free to leave a comment. I’d really appreciate feedback. Architecture Overview Tech Stack Next.js 14 (App Router) — server components, layouts TypeScript Tailwind CSS Zustand for local state viem and wagmi for on-chain interactions App Router inside Base App: Important Constraints Inside Base App, you cannot rely on standard web assumptions: full SSR is not available (part of the environment is restricted); unstable fetch calls (some origins are blocked); system navigation (window.location) is not allowed — everything must stay inside the mini-app sandbox. Base App is very friendly to Vercel, so deployment was straightforward. Critical rules: use export const dynamic = "force-dynamic"; when UI must update on every request; avoid window-dependent logic in server components; keep heavy API logic inside /api/* routes. Backend Layer: API, KV, and Off-Chain Data Posts live off-chain — otherwise the mini app would be painfully slow when loading the feed. Storage Vercel KV — main production storage local JSON file — development mode Data Placement DataWhereWhyPostsKVFast, almost freeReactionsKVLow trafficWinners historyKVNo need to be on-chainPost ↔ NFT mappingForumNFT contractMost valuable data Smart Contracts: ForumNFT and Marketplace on Base Mainnet All production contracts of The Wall Base are deployed on Base mainnet. What is Base? Base is an Ethereum Layer 2 rollup developed by Coinbase, built on the OP Stack. This gives us: full EVM compatibility (Solidity, Hardhat, Foundry); significantly lower fees than Ethereum mainnet; fast transaction finality; native integration with Coinbase and Base App. For mini apps, Base is almost ideal: cheap gas, fast UX, Ethereum-level security. Why Development Was Done on Base Sepolia Even though production runs on Base mainnet, all development and testing happened on Base Sepolia, the Base testnet. Reasons are straightforward: contract deployment costs real ETH; every logic mistake costs money; testnet behavior mirrors mainnet almost exactly. Deploying a simple ERC-721 contract on Base mainnet typically costs $5–10, depending on complexity and network load. So all logic — from minting to prize pool — was fully tested on testnet first. How Contract Deployment Actually Works This is something beginners often misunderstand. A smart contract is not deployed from an IDE. Deployment flow: written locally (Solidity); compiled locally (Hardhat); sent to the network via an EVM wallet. You need: a wallet private key; a network RPC endpoint; ETH balance (testnet or mainnet). Deployment is just a regular transaction that sends contract bytecode to the network. npx hardhat run scripts/deploy.js --network base Test ETH for Base Sepolia To use Base Sepolia, you need test ETH. I used the Alchemy faucet: https://www.alchemy.com/faucets/base-sepolia Important caveat: it usually works only for wallets with mainnet activity. I couldn’t find a faucet that reliably sends ETH to brand-new wallets. An alternative is bridging ETH from Ethereum testnet to Base Sepolia using testnet bridges — these exist, but for beginners it’s another quest. If you’re stuck — ask in the comments, I’ll try to point to currently working bridges. On-Chain vs Off-Chain Separation The project clearly separates two layers. On-chain smart contracts (ForumNFT, Marketplace); funds custody; NFT ownership; prize pool. Off-chain frontend (Next.js); post storage; winner selection; UI/UX; RPC interaction. Contracts are deployed independently from the frontend and communicate via RPC. Moving from Base Sepolia to Base Mainnet Once contracts were fully tested on Base Sepolia, moving to mainnet was simple: Deploy contracts to Base mainnet Get new contract addresses Update frontend configuration # beforeNEXT_PUBLIC_BASE_RPC_URL=https://sepolia.base.orgNEXT_PUBLIC_NFT_CONTRACT_ADDRESS=0xTestAddress # afterNEXT_PUBLIC_BASE_RPC_URL=https://mainnet.base.orgNEXT_PUBLIC_NFT_CONTRACT_ADDRESS=0xMainnetAddress Thanks to EVM compatibility, contract behavior is identical — although the migration still had pitfalls, which I’ll describe below. ForumNFT: Custom ERC-721 Key features: minting at a fixed price; 50% → rewardPool, 50% → ownerBalance; mappings between posts and tokens; service values: nextTokenId MIN_REWARD_RESERVE = 0.0001 ether adminSetNextTokenId function adminSetNextTokenId(uint256 value) external onlyOwner Why it exists: During beta testing, mini apps generate many temporary posts. I periodically burned the entire collection and reset state — which required resetting nextTokenId. ⚠ If called without a full burn → token ID collisions are possible. Marketplace NFT listings with price purchases with commission part of the fee goes to rewardPool all trades are standard ETH transactions (cheap on Base) Prize Pool Logic The pool is funded by: minting (50%)+ marketplace fees+ ownerBalance (manual top-ups) A 0.0001 ETH reserve is always preserved — otherwise the pool could hit zero and break ETH/USD price queries. Why the Raffle Is Off-Chain Base Mini Apps: don’t support on-chain randomness; have no built-in VRF; can’t force users to wait for Chainlink callbacks. Implementation: /api/reward/draw selects a random post (PRNG + filters); sends payPrize(winner, tokenId, amount) transaction; stores winner history in KV. Farcaster Mini App SDK Integration Used methods: sdk.actions.openUrl() — open user profil sdk.actions.openPage() — internal navigation sdk.ready() — required before rendering UI Constraints: no window.location navigation; links must be whitelisted in the manifest; only base.app and farcaster.xyz links are clickable. RPC: Why Nothing Worked on Mainnet at First This was one of the most painful issues. Marketplace NFTs wouldn’t load, prize pool wouldn’t update. The root cause was public RPC throughput limits. What I tried initially https://mainnet.base.org https://developer-access-mainnet.base.org shared Infura / Alchemy endpoints Problems: 4–7s timeouts on reads; unstable viem/wagmi responses; random execution reverted; eth_call worked while eth_sendTransaction failed; additional rate limits inside Base App WebView. For mini apps, this is fatal. Solution: Private RPC from Coinbase Developer Platform Normally private RPCs are paid, but Coinbase Developer Platform provided them for free, plus: $500 in USDC credits gas fee rebates for app users Private endpoint: https://base-mainnet.g.alchemy.com/v2/ Used as: NEXT_PUBLIC_BASE_RPC_URL= Results: response time dropped to 90–120 ms; no missed eth_call; stable mobile behavior; marketplace loaded consistently; prize pool updates became reliable. Mini apps are extremely latency-sensitive — the difference was dramatic. Admin Panel: Technical Details Admin features: view ownerBalance; manage fees; manual prize draw; reset token counter; hide posts (moderation); mark featured posts (highlight key ecosystem users). Security: frontend checks ADMIN_ADDRESS; real protection is on-chain via onlyOwner. Mini App Manifest and Assets File: public/.well-known/farcaster.json { "name": "The Wall Base", "description": "Farcaster mini-app: NFT posts, marketplace, prize pool", "iconUrl": "/200_00000.png", "splashUrl": "/1024_00000.png", "developer": "base.app/"} For development, noindex=true is required — otherwise the manifest gets cached. Common Issues and Fixes 1. wagmi + mini app environment You cannot rely on window.ethereum. Use the Base App connector. 2. BigInt in React state BigInt inside JSON can crash WebView. Serialize to string. 3. ETH → USD rate CoinMarketCap rate-limits aggressively. Cache for ~30 minutes. Deployment Contracts (Hardhat) npx hardhat run scripts/deploy.js --network basenpx hardhat verify --network base Frontend (Vercel) root: /miniapp build: npm run build env: private RPC + contract addresses Conclusion What started as an experiment became a real product: a social network — where every post is an NFT; a marketplace — embedded directly into a mini app; a prize pool — fully on-chain; Base App integration — feels like a native mobile app. Base Mini Apps open a huge opportunity for hybrid dApps. If you’re interested in building on Base App, check the links below. Links Base App (invite): https://base.app/invite/mynameisthe/X5W2YTPB Base Docs: https://docs.base.org/get-started/base The Wall Base: https://basewall.vercel.app/ My baseapp account — a fundamental analysis of coins and earnings on AirDrops. I buy cryptocurrency on Bybit ## Publication Information - [Mario](https://paragraph.com/@tortmario/): Publication homepage - [All Posts](https://paragraph.com/@tortmario/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@tortmario): Subscribe to updates - [Twitter](https://twitter.com/Tort_Mario): Follow on Twitter