← All Case Studies Web3 / DeFi

MeowFi DeFi Monorepo

Learn how I scaled MeowFi into a full-stack DeFi monorepo. Covers tRPC contracts, multicall data pipelines, and resilient wallet transaction UX patterns.

February 10, 2025 Updated March 19, 2026
MeowFi DeFi Monorepo

Project Overview

MeowFi is a DeFi application on Monad that combines yield vaults, liquidity pools, token swaps, referral mechanics, and NFT-gated role verification.

I joined to build frontend product surfaces, then expanded ownership into backend architecture and protocol data flows. The project evolved into a full-stack monorepo with shared type contracts and production-focused transaction handling.

Scope and Ownership

  • Designed and shipped a feature-based React frontend covering vaults, pools, swaps, dashboard, and verification flows.
  • Architected the backend API surface with Express + tRPC routers for vaults, assets, tokens, referrals, and role assignment.
  • Built and maintained on-chain data pipelines using Viem multicall and server-side aggregation.
  • Implemented transaction orchestration patterns with neverthrow for safer multi-step wallet interactions.

Core Engineering Challenges

  1. RPC fan-out and latency: Vault UIs required many independent contract reads. Naive per-field calls introduced high latency and brittle client logic.
  2. Unstable first render: Vault card metadata and live vault stats arrived at different times, causing inconsistent initial render behavior.
  3. Error-prone transaction flows: Approval, Permit2 setup, swaps, and deposits are multi-step processes where partial failures are common.
  4. Cross-system identity complexity: Wallet ownership, Discord identity, JWT auth, and NFT role eligibility had to stay consistent across systems.

Engineering Solutions

1) Monorepo and Typed API Contracts

I moved the project to an NPM workspaces monorepo (apps/frontend, apps/backend) and standardized communication through tRPC.

  • Implementation: Frontend tRPC hooks are generated from backend AppRouter types, giving compile-time guarantees across request/response boundaries.
  • Outcome: Backend schema changes surfaced immediately in frontend compile errors instead of runtime breakage.

2) High-Throughput On-Chain Reads with Multicall

I centralized blockchain reads in backend procedures and replaced scattered reads with batched calls.

  • vault.bribe.liveStats batches 16 vault getters per vault into one multicall request.
  • asset.userAssets composes large batched reads for vault positions, bribes, pool balances, and BPT rates in a single execution path.
  • token.userBalance, token.prices, and asset.homePage also use multicall patterns to keep frontend queries lean.

This removed RPC fan-out from the client and made dashboards materially faster and more consistent under load.

3) Stable Rendering via Static Metadata + Live Hydration

I separated static vault metadata from volatile on-chain stats.

  • Static layer: Vault definitions (title, images, NFT info, addresses) are declared in local feature data files.
  • Dynamic layer: APY, periods, balances, and live protocol stats are hydrated asynchronously through tRPC queries.

This preserved deterministic layout while still delivering real-time protocol data.

4) Result-Based Transaction Pipeline with neverthrow

I replaced nested try/catch flows with ResultAsync pipelines for wallet interactions.

  • Shared utility layer: Approval checks, Permit2 approval, spender approval, tx submission, and receipt confirmation were wrapped into composable result functions.
  • UI behavior: Components chain these steps with .andThen(...) and emit explicit toast stages (approval, execution, confirmation, success/failure).

This made transaction behavior easier to reason about and significantly improved failure visibility for users.

5) Hybrid Analytics Pipeline for Liquidity Pools

I built a backend job that computes and persists pool analytics consumed by the frontend.

  • A scheduled process computes TVL, volume, fees, APR/APY, and daily series using on-chain reads plus indexed swap/liquidity events.
  • Results are stored in MongoDB and served via vault.liquidityPool.stats for fast dashboard rendering.

6) Auth and Role Verification Across Wallet + Discord

I implemented verification flows that bridge Web3 ownership with community permissions.

  • Discord OAuth callback issues JWTs for authenticated API access.
  • Protected role assignment verifies signed wallet messages, checks ERC721 ownership on-chain, binds wallet addresses, and assigns mapped Discord roles.
  • A scheduled reconciliation process removes roles when NFT ownership is no longer valid.

Results and Impact

  • Type-safe delivery: Frontend and backend development moved faster with fewer integration regressions.
  • Performance: Core DeFi views shifted from many client-side RPC calls to batched server-side reads.
  • Reliability: Multi-step transactions became explicit, traceable, and user-friendly under failure conditions.
  • Scalability: Feature-first modules and domain routers supported growth across vaults, pools, referrals, and verification without architectural rewrites.

Architecture Snapshot

apps/
  frontend/
    src/
      app/                 # Routing, providers, app wiring
      features/
        bribeVault/
        meowPools/
        userDashboard/
        verifyRole/
      shared/              # Reusable UI, data, utilities
  backend/
    src/
      routers/
        vaults/            # bribe, autoCompound, liquidityPool
        asset/
        token/
        referral/
        role/
      setup/               # viem client, discord, analytics jobs
      models/              # MongoDB schemas