Catalyst · Architecture

System architecture

Catalyst is built as a split system: a set of immutable smart contracts on Base that hold state and enforce rules, plus a set of off-chain services that index, observe, and react to on-chain events. This page maps every component, what it does, and how they talk to each other.

High-level topology

ON-CHAIN (Base Sepolia)

• CatalystRegistry — startup metadata + lifecycle

• CatalystHook — Uniswap v4 hook with custom fee logic

• PerformanceEvaluator — settlement decision contract

• CollateralVault — founder collateral + claims

• CatalystAdoptionScorer — verdict storage

• CatalystEvaluatorRegistry — staked evaluators (ERC-8183)

• Uniswap v4 PoolManager — Pool 1 (USDx/USDy) + Pool 2 (USDx/TOKEN)

• MockUSDx, MockUSDy — testnet stablecoins

OFF-CHAIN (server)

• Backend indexer (Express + SQLite)

• scorer-oracle daemon (the adoption oracle)

• notifications daemon (Slack / Telegram)

• Frontend (Next.js) — this site

OFF-CHAIN (user machine)

• catalyst-MCP server — Claude Desktop integration

• Wallet (MetaMask / WalletConnect)

On-chain contracts

CatalystRegistry

The central entry point. Stores all startup data (founder address, token address, collateral amount, commitment deadline, minimum price target, status) and owns the startup ERC-20 token contracts. Every lifecycle transition goes through the registry: registerStartup, closeFunding, completeStartup, failStartup.

CatalystHook

A Uniswap v4 hook contract deployed at a precomputed address whose hash encodes which hook permissions it uses. Implements three hook callbacks:

  • beforeInitialize — only allows pools to be initialized via the registry (prevents random users from creating rogue pools that impersonate a startup)
  • afterSwap — intercepts the fee output of every Pool 1 swap and splits it 70/30 between founder operational funding and automatic token buyback in Pool 2
  • afterAddLiquidity — records investor positions when they deposit, for later claim / withdraw accounting

The hook is also the entry point for the frontend's fundStartupflow — it wraps the liquidity deposit plus the token allocation mint in a single user transaction.

PerformanceEvaluator

A pure on-chain evaluator. It reads three things at settlement time: current token price from Pool 2 via StateView, minimum price target from the registry, and the current adoption verdict from the scorer. It returns SUCCESS (price >= target AND verdict != DENY) or FAILED. No human judgment, no delay, no oracle outside of the adoption scorer.

CollateralVault

Holds founder collateral in escrow for each startup. When a startup is registered, ETH is transferred here. On SUCCESS, the founder can reclaim. On FAILURE, investors can file claims against it pro-rata. This is the ERC-8210 JobAssurance implementation — claim lifecycle, upstream fields, reasoning CIDs.

CatalystAdoptionScorer

The on-chain part of the adoption oracle. One function for the oracle to write (postScore), one function for everyone to read (getVerdict). Only the oracle address can write. See Adoption oracle for the full story.

CatalystEvaluatorRegistry

The ERC-8183 evaluator registry. Evaluators stake ETH, attest to job outcomes, and can be slashed if their attestations contradict reality. Currently the primary evaluator is the PerformanceEvaluator contract itself (which doesn't need to stake because it is deterministic), but the registry exists to support optional additional human or agent evaluators.

Off-chain services (server)

Backend indexer

Express + better-sqlite3, living in packages/backend/. It subscribes to the Base Sepolia RPC, listens for every relevant event from the Catalyst contracts (StartupRegistered, InvestorFunded, FeesDistributed, ClaimFiled, Slashed, ScorePosted, PerformanceEvaluated), and writes them into a local SQLite database.

On top of that, it exposes a REST API consumed by the frontend: protocol stats, per-startup history, investor dashboards, evaluator registry state, oracle history. The database is a caching layer — if it gets wiped, the indexer replays from block 0 and rebuilds it from on-chain state.

scorer-oracle daemon

Lives in packages/scorer-oracle/. Combines a ManualCollector (YAML-backed seed data for bootstrap) and an OnChainCollector that reads Transfer events and swap events to compute adoption metrics. On each run it decides a verdict, publishes reasoning to IPFS, and signs an on-chain transaction with ORACLE_PRIVATE_KEY. Runs as a PM2 process, one cycle every few minutes.

Notifications daemon

Lives in packages/notifications/. Opens the backend SQLite database in read-only mode, polls every 30 seconds for new rows in the event tables, and posts formatted alerts to Slack (and optionally Telegram) webhooks. At-most-once delivery — failed posts don't retry, they log.

Frontend

Next.js 16 in packages/frontend/. Uses wagmi + viem for wallet connections and contract reads, the Uniswap v4 SDK for PositionManager interactions, and talks to the backend indexer for historical data. The docs you are reading now are part of this frontend.

Off-chain services (user machine)

catalyst-MCP server

A Model Context Protocol server that Claude Desktop (or any other MCP-compatible AI client) spawns locally. It exposes Catalyst actions as MCP tools so an agent can register startups, fund them, file claims, and read protocol state through natural conversation. The MCP server signs transactions locally using keys from the user's .env— the keys never leave the user's machine. See MCP docs for details.

Data flow examples

Investor funds a startup

1. Frontend form collects USDx + USDy amounts

2. Wallet signs permit2 approval + fundStartup tx

3. CatalystHook.fundStartup executes on-chain

— pulls stables via permit2

— adds liquidity to Pool 1

— mints investor token allocation

— emits InvestorFunded event

4. Backend indexer picks up the event, inserts row

5. Notifications daemon reads the new row, posts to Slack

6. Frontend dashboard refetches, shows the new position

Oracle publishes a DENY verdict

1. Oracle daemon wakes up on cron tick

2. Reads Transfer events + Pool 2 swaps for every active startup

3. Computes holder count, swappers, volume, wash score, retention

4. Startup X fails 4 of 5 thresholds → DENY 70%

5. Writes reasoning JSON to IPFS → receives CID

6. Signs postScore(X, 2, 70, cid) with ORACLE_PRIVATE_KEY

7. Tx confirms → CatalystAdoptionScorer state updated

8. Indexer picks up ScorePosted event, writes to scores table

9. Notifications daemon posts to Slack: “Adoption score posted — Startup X: DENY”

10. At settlement, PerformanceEvaluator reads DENY and marks the job FAILED

Deployment addresses

All contracts are deployed on Base Sepolia (chain id 84532) and verified on Basescan. The current addresses are visible in the Admin dashboard of this site and in the frontend's env.localfile. If you are building against Catalyst, fetch them from the frontend's NEXT_PUBLIC_* environment variables rather than hardcoding.