ARCHITECT.LOGConnect
System Architecture2026

Campus Event Credits & Ticketing dApp

A full-stack Hardhat-based Ethereum dApp that mints ERC-20 campus credits and issues non-transferable ERC-721 event tickets via a role-gated EventPlatform with a React ethers.js SPA frontend.

System snapshot

EventPlatform-orchestrated credits-to-soulbound-tickets ticketing with per-event treasury accounting

CreditsToken (ERC-20) mint/burn restricted to EventPlatform; users buy credits by sending ETH to EventPlatform

EventPlatform coordinates platform-gated minting and wiring across tokens and treasury

TicketNFT (ERC-721) is non-transferable by overriding approval/transfer functions; tickets track Active/Invalidated/Refunded/Used

TreasuryVault records paidCreditsByEvent and refundCreditsByEvent per event ID; only platform writes

Organizer/admin-controlled event lifecycle and tier configuration (Draft → OnSale → SoldOut, plus guards)

React SPA role detection + UI flows (wallet connect, approve ERC-20 allowance, purchase tickets, admin/organizer consoles)

Design focus

  • Non-transferable (soulbound) ERC-721 enforced by reverting approval/transfer methods
  • Platform-gated minting and restricted writes (EventPlatform as the only minter/writer)
  • Event state machine with guard checks blocking tier/wallet-cap changes after leaving Draft
  • CEC unit discipline using parseEther/parseUnits to keep ERC-20 base units consistent
  • On-chain auditable accounting via per-event treasury records

Context

The Architectural Challenge

Campus events often rely on centralized ticketing that provides no strong on-chain ownership guarantees, enabling secondary resale and ticket fraud. This project explores enforcing ticket non-transferability and per-wallet purchase limits directly in smart contract logic, using an ERC-20 campus credits token (CEC) instead of raw ETH for ticket purchases, while keeping the system auditable on-chain through a per-event treasury record.

Project parameters

Domain
Blockchain
Type
Project
Complexity Level
Intermediate

Technology stack

Solidity 0.8.28OpenZeppelin Contracts v5Hardhat 3@nomicfoundation/hardhat-toolbox-mocha-ethersTypeScript 5.8Mocha 11Chai 6ethers.js v6@nomicfoundation/hardhat-ethersReact 19Vite 7Bulma 1.0React Router 7

Core Innovation

The system combines an ERC-20 credits economy with non-transferable ERC-721 tickets under a single coordinating EventPlatform contract, creating a closed-loop flow: credits are only spent to obtain tickets, tickets cannot leave the purchasing wallet due to contract-enforced soulbound behavior, and per-event treasury mappings provide an auditable record of CEC paid and refunded. This design lets a standard OpenZeppelin composition implement domain-specific constraints (soulbound tickets and gated issuance) without custom base primitives.

Implementation

Implementation Details

The architecture is split into four Solidity contracts: CreditsToken (ERC-20 with 18 decimals, symbol CEC) and TicketNFT (ERC-721) are both platform-minted; only the registered EventPlatform can mint or burn for CreditsToken, and only the platform can mint/invalidate/mark used/mark refunded for TicketNFT. TicketNFT enforces non-transferability by overriding approve, setApprovalForAll, transferFrom, and safeTransferFrom to revert with a NonTransferable custom error.

TreasuryVault maintains per-event accounting using paidCreditsByEvent and refundCreditsByEvent mappings; writes are restricted so only EventPlatform updates these records.

EventPlatform acts as the coordinator: admin approves organizers; organizers create events and configure ticket tiers (tier label, CEC price, max supply), set per-event wallet caps, and transition event lifecycle states (Draft → OnSale → SoldOut, with additional cancellation/completion states referenced). Students buy credits by sending ETH to EventPlatform.buyCreditsWithEth() (mints CEC at ethToCreditsRate), then follow a two-transaction ERC-20 approval pattern—approve allowance to EventPlatform and call obtainTicketWithCredits to receive a TicketNFT.

On the frontend, the repository provides a React + Vite SPA using ethers.js v6 and Bulma. The SPA is role-aware and detects admin/organizer/student roles by reading eventPlatform.admin() and eventPlatform.approvedOrganizers(account) on wallet connection/network changes. The SPA uses a local deployment script (deploy-spa-local.ts) to deploy contracts and write deployed addresses plus parsed ABIs into spa/src/config/contract-info.json so the UI has a single source of truth without hardcoding addresses. The user flows include credit purchase, ERC-20 allowance checking/approval before ticket purchase, organizer studio actions (create event, add tiers, set wallet cap, start sales), an admin console (approve organizers, update exchange rate), a wallet dashboard, and a ticket inventory. Tests (Mocha/Chai) cover contract components, access control rejections, state transitions, and misuse scenarios for non-transferability, plus an end-to-end scaffold.

Latency profile

Local Hardhat node: instant finality (EDR-simulated network)

All transactions confirm in the same block on the local EDR-simulated Hardhat network; there is no real block-time latency. The practical bottleneck is the React state refresh cycle after each transaction receipt, rather than on-chain confirmation time.

System focus

Correctness and access control with soulbound enforcement

The engineering emphasis is on correctness of role-gated access control, lifecycle guards, and enforcing non-transferable ticket behavior directly at the contract level. The contracts use custom errors for clearer reverts and improved deployment cost versus string reverts, and the Hardhat profile is set up to keep development feasible without optimizer by default, while a production Hardhat profile enables the optimizer at 200 runs.

Outcomes

Outcomes & Future Iterations

The contract suite enforces ticket non-transferability, per-wallet purchase caps, and CEC-denominated pricing entirely on-chain. The SPA provides end-to-end interaction across unconnected visitors, students, organizers, and admins, including on-chain state reads, two-step ERC-20 approval-based purchase flows, organizer/admin consoles, and transaction evidence panels that show hash, receipt status, block number, gas used, and balance changes for confirmed transactions.

Why this matters

This project demonstrates how composable OpenZeppelin primitives (ERC-20, ERC-721, Ownable) can be adapted into a domain-specific system with non-standard behavior—specifically making NFTs intentionally soulbound—while maintaining auditable on-chain constraints. The role-detection approach and event state machine patterns are directly reusable for other gated access systems that need correctness, traceability, and contract-enforced policy rather than relying on off-chain enforcement.