Skip to content

AuronCrow10/BlockEstate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BlockEstate 🏠🔗

A full-stack Web3 real-estate demo that showcases:

  • Fractional ownership of properties via ERC-1155
  • On-chain governance (SELL / RESTRUCTURE / LOAN) with token-weighted voting
  • Exit rounds where new buyers come in and existing holders cash out
  • A backend indexer that listens to smart contract events over WebSockets and keeps a Postgres database in sync
  • A Next.js dApp that talks directly to contracts for critical actions (buys, votes, proposals)

⚠️ Educational / demo only.
No real assets, no real investment products.
Do not use with real funds or deploy to mainnet.


🧠 What this project demonstrates

Smart contract skills

  • Modular Solidity architecture on Sepolia:

    • PropertyToken1155 (ERC-1155) for fractionalized properties:
      • Each tokenId = one property
      • Primary sale via buyShares
      • Tracks maxSupply, totalSupply, and pricePerToken
    • PropertyGovernance:
      • Enum-based proposal types: SELL, RESTRUCTURE, LOAN
      • Token-weighted voting and quorum / majority checks
      • executeProposal wired into valuation + exit logic
    • PropertyValuationRegistry:
      • On-chain reference price per token, updatable via governance
    • PropertyExitSale:
      • Exit rounds at a governance-approved price
      • New buyers deposit ETH, old holders surrender tokens & claim ETH
  • Ownership & roles wiring:

    • Governance owns the token, valuation registry and exit sale
    • Only governance can set valuations and trigger exits
  • Hardhat workflows:

    • Single deploy script that:
      • Deploys all contracts
      • Wires ownership / addresses
      • Verifies contracts on Etherscan after deploy

Backend & indexing skills

  • Node.js + TypeScript + Express as a REST API for:

    • Auth (JWT, email/password)
    • Off-chain property & proposal metadata
    • Portfolio / positions views
  • Prisma + PostgreSQL schema modeling:

    • User, Property, Investment, Proposal, Vote
    • Off-chain metadata for on-chain entities:
      • Proposal.onchainId, startBlock, endBlock, state
      • Investment.txHash + logIndex with uniqueness constraint
      • Property.referencePricePerTokenWei, referencePriceUpdatedAt
  • WebSocket-based indexer (via viem):

    • Subscribes with watchContractEvent to:
      • PropertyGovernance.ProposalCreated
      • PropertyGovernance.VoteCast
      • PropertyGovernance.ProposalExecuted
    • Uses watchBlockNumber to track the current chain height
    • Keeps the DB in sync with:
      • On-chain proposals (mapping metadataURI → DB rows)
      • Vote weights & histories
      • Proposal state transitions (ACTIVE → EXECUTED / DEFEATED)
  • Hybrid flow:

    • Users now directly call PropertyGovernance.createProposal from the frontend
    • The backend indexer listens to events and discovers / stores proposals coming from any wallet
    • API reads from Postgres and can optionally enrich with on-chain getProposal calls

Frontend / dApp skills

  • Next.js (App Router) + React + TypeScript

  • wagmi + viem for:

    • Direct on-chain actions:
      • buyShares on PropertyToken1155
      • createProposal, vote, executeProposal on PropertyGovernance
      • Exit flows on PropertyExitSale:
        • buyForExit
        • claimExit
        • claimExitTokens
    • Reads via usePublicClient:
      • maxSupply, totalSupply, pricePerToken
      • Valuation data from PropertyValuationRegistry
      • Exit state and per-user entitlements from PropertyExitSale
  • UX that respects chain rules:

    • "Can vote?" depends on:
      • Wallet connected
      • Proposal state = ACTIVE
      • User ERC-1155 balance > 0 for that tokenId
    • "Can create SELL proposal?" depends on:
      • Wallet connected
      • Holder balance ≥ 20% of maxSupply (mirrors the Solidity check)
    • "Can execute?" depends on:
      • Proposal state = ACTIVE
      • Current block number (tracked via watchBlockNumber) being greater than endBlock
  • Tailwind UI:

    • Property detail page:
      • On-chain stats cards
      • Holdings summary
      • Exit sale panel (progress, join, claim)
      • Governance panel (proposals list + modal to create SELL proposals)
    • Proposal detail page:
      • Human-readable state & type mapping
      • Vote counts
      • Voting buttons with clear pending / error states
      • Smart “Execute proposal” section that only enables the button once on-chain conditions are met

🧱 High-level architecture

Contracts (Sepolia)

  • PropertyToken1155
  • PropertyGovernance
  • PropertyValuationRegistry
  • PropertyExitSale

Backend (Express + Prisma)

  • Exposes JSON APIs under /api for:
    • Auth
    • Properties
    • Proposals
    • Investments
    • Portfolio / “me”
  • Uses:
    • Prisma for all DB access
    • viem for:
      • RPC reads (readContract)
      • WebSocket subscriptions (watchContractEvent, watchBlockNumber)

Frontend (Next.js dApp)

Rough structure:

  • app/

    • page.tsx — Landing
    • properties/page.tsx — Properties list
    • properties/[id]/page.tsx — Property detail:
      • Invest, exit sale, holdings & governance section
    • proposals/[id]/page.tsx — Proposal detail, voting & execution
    • dashboard/page.tsx — User portfolio view
    • admin/properties/page.tsx — Admin panel for property approvals
  • abis/ — TypeScript ABIs for all contracts

  • lib/api.ts — Axios client configured with backend URL

  • lib/wagmi.tsx — wagmi config for Sepolia + MetaMask etc.


🧪 Governance & exit flow (conceptual)

1. Primary sale

  • Admin approves property in the backend
  • Backend calls the token contract to createProperty (assigns tokenId, maxSupply, pricePerToken)
  • Users invest via buyShares(tokenId, amount) from the frontend

2. Governance (SELL example)

A large holder (≥ 20% of max supply for that tokenId) creates a SELL proposal:

  • Frontend calls
    PropertyGovernance.createProposal(tokenId, ProposalType.SELL, proposedPricePerTokenWei, metadataURI)
  • metadataURI points back into the backend (JSON with title/description or simply the DB id)

Other holders vote YES/NO:

  • Voting power = ERC-1155 balance at call time

executeProposal can be called by anyone once:

  • block.number > endBlock
  • Quorum is met
  • YES ratio > configured threshold

If passed:

  • Governance updates PropertyValuationRegistry with the reference price
  • Governance optionally calls PropertyExitSale.openExit:
    • Sets exit price
    • Sets targetTokens for the exit round

3. Exit round

  • New buyers call buyForExit with ETH at the exit price
  • Old holders:
    • Approve the exit sale contract for their ERC-1155 tokens
    • Call claimExit to surrender tokens and receive ETH
  • New buyers:
    • Call claimExitTokens after enough tokens have been surrendered

4. Indexing

The backend indexer subscribes over WebSockets to governance and exit events, and:

  • Creates / updates Proposal rows on ProposalCreated
  • Creates Vote rows on VoteCast
  • Updates proposal state on ProposalExecuted
  • Maps log index + tx hash to avoid duplicates
  • Keeps off-chain views (e.g. proposal lists in the UI) stateless and fast

🚀 Quickstart (dev)

This is intentionally high-level; exact env vars / scripts live in each subfolder.

1. Deploy contracts (Hardhat)

Inside contracts/:

  • Configure .env with:
    • SEPOLIA_RPC_URL
    • PRIVATE_KEY
    • ETHERSCAN_API_KEY

Then:

npm install
npm run build
npm run deploy

The deploy script:

  • Deploys PropertyToken1155, PropertyValuationRegistry, PropertyGovernance, PropertyExitSale
  • Transfers ownership of token + valuation + exit sale to governance
  • Links governance to exit sale
  • Verifies contracts on Etherscan (Sepolia)
  • Prints the addresses and a .env-friendly summary

Copy those addresses into:

  • backend/.env

    • GOVERNANCE_ADDRESS=0x...
    • PROPERTY_TOKEN_ADDRESS=0x...
    • PROPERTY_VALUTATION_REGISTRY_ADDRESS=0x...
    • PROPERTY_EXIT_SALE_ADDRESS=0x...
  • frontend/.env

    • NEXT_PUBLIC_GOVERNANCE_ADDRESS=0x...
    • NEXT_PUBLIC_PROPERTY_TOKEN_ADDRESS=0x...
    • NEXT_PUBLIC_PROPERTY_VALUTATION_ADDRESS=0x...
    • NEXT_PUBLIC_PROPERTY_EXIT_SALE_ADDRESS=0x...

2. Backend (API + indexer)

Inside backend/:

  • Configure .env:
    • DATABASE_URL
    • JWT_SECRET
    • RPC URL (for viem)
    • Contract addresses (from deploy step)

Then:

npm install
npx prisma migrate dev
npm run dev

This will:

  • Start the Express API
  • Connect to Postgres
  • Start the event indexer via WebSockets

3. Frontend (Next.js dApp)

Inside frontend/:

  • Configure .env:
    • NEXT_PUBLIC_API_URL (pointing to the backend)
    • NEXT_PUBLIC_* contract addresses

Then:

npm install
npm run dev

Open http://localhost:3000 and you can:

  • Browse properties and invest
  • Create SELL proposals (if you hold enough)
  • Vote with your ERC-1155 balance
  • Execute proposals once the voting period ends
  • Participate in exit rounds as old or new holder

⚠️ Disclaimer

This is not financial advice and not production-ready code.
It’s a learning / portfolio project that demonstrates:

  • Solidity contracts wired together into a coherent protocol
  • A full-stack dApp with governance, exits, and indexed on-chain data
  • Using WebSockets + viem to maintain an off-chain view in Postgres
  • A Next.js / React UI with wallet integration and on-chain UX patterns

Use it to learn, fork, and experiment — not to handle real money.

About

Full-stack Web3 real-estate demo with ERC-1155 fractional ownership, on-chain governance, exit rounds, and event-indexed off-chain state.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors