Skip to content

evayou0915/Ethglobal

Repository files navigation

AuraSci — Milestone-Based Open-Science Funding on Base

From Proof to Capital. Scientists publish 3-milestone research intents, patrons fund them in USDC, an AI gatekeeper screens publish-time and an AI verifier grades each milestone proof straight from Walrus storage — capital is released tranche-by-tranche from a Solidity escrow on Base, only after a verifier signature.

Base Next.js Hono Prisma Walrus Claude Privy License


🔗 Live demo

App https://aurasci-ethglobal.vercel.app
Backend API https://aurasci-api-production.up.railway.app (Railway · always-on)
Escrow contract (Base Sepolia) 0x69F15fafEF08a6Fb7fBF28e0F92467a5532F1812
USDC (Base Sepolia) 0x036CbD53842c5426634e7929541eC2318f3dCF7e
Chain Base Sepolia (84532)
AI verifier Anthropic Claude (claude-haiku-4-5) — real proof grading in llm mode
Release signer Privy server wallet 0xA7084d5e27043F4126C161c8a31eF6D0efDca5Cd — signs EIP-712 releases, policy-restricted

Sign in with a browser wallet (MetaMask / Rabby) on Base Sepolia; grab test ETH + USDC from the in-app faucet links. Frontend on Vercel, backend (api + chain indexer + AI worker) + Postgres on Railway — both always-on, no local host required. The Canton private rail is local-only (run daml start in canton/); the Base + Walrus + Claude flow is live.


🧬 What this is

Grant funding takes 9–18 months and pays in lump sums with no accountability after the cheque clears. AuraSci replaces the cheque with a programmable USDC escrow on Base that releases capital milestone by milestone, gated by AI verification of the proof a scientist submits.

Three primitives:

Primitive What it is Where it lives
Intent A research proposal with funding goal + 3 milestones DB row + on-chain escrow accounting
Patronage A patron's USDC deposit toward an intent Deposited event → DB row
Milestone release A tranche payout to the scientist after AI verification Released event signed by the AI verifier key

No tokens, no governance noise — just verified milestone → released capital.

A parallel Aura social-points layer (backend/src/lib/aura.ts) runs alongside escrow: patrons spend season-budgeted Aura to "boost" intents they believe in, and earn yield Aura when those intents hit milestones. Pure off-chain reputation, no on-chain token.


🏛 Architecture

┌──────────────────┐        ┌────────────────────────────────────┐
│  Next.js front   │  HTTPS │   Hono backend (self-hosted)        │
│  (Vercel)        │◀──────▶│                                     │
│  - SIWE auth     │        │  ┌──────────┐  ┌──────────┐         │
│  - wagmi/viem    │        │  │  /api/*  │  │ ai-worker│         │
│  - injected w.   │        │  │   Hono   │  │  (LLM    │         │
└────────┬─────────┘        │  └────┬─────┘  │  jobs)   │         │
         │ writeContract     │       │        └────┬─────┘         │
         ▼                   │       ▼             │               │
┌──────────────────┐         │  ┌─────────────────────────────┐    │
│ AuraSciEscrow.sol│◀────────┼──│  Postgres  (Prisma client)  │    │
│ on Base (USDC)   │         │  └─────────────────────────────┘    │
│ - deposit        │         │                ▲                    │
│ - release(sig)   │         │  ┌─────────────┴────┐               │
│ - refund(sig)    │         │  │     indexer      │ ── viem ──┐   │
│ - adminWithdraw  │         │  │ (event watcher)  │           │   │
└────────┬─────────┘         │  └──────────────────┘           │   │
         │ Deposited/        └──────────────────────────────────│──┘
         │ Released/                                            │
         │ Refunded                                             │
         └───────────────────────── Base RPC ───────────────────┘

The contract is a vault. The DB is the ledger. Walrus is the archive. All intent metadata, AI scores, Aura points and activity logs live in Postgres. Proof artifacts (papers, datasets, figures) are stored as Walrus blobs — the DB keeps only their blobId + SHA-256. The contract only knows: balances keyed by intentId, the AI verifier's public key, and the admin's address.

Components

Layer Path Stack
Frontend src/ Next.js 14 App Router + wagmi/viem + SIWE wallet login
Canton rail canton/ Daml templates for ledger-private patronage (see canton/README.md)
Backend API backend/src/server.ts Hono on Node 20
Chain indexer backend/src/indexer.ts viem watchContractEvent
AI worker backend/src/ai-worker.ts Anthropic Claude grader + EIP-712 signer
Proof storage backend/src/lib/walrus.ts Walrus HTTP publisher/aggregator (blobs certified on Sui)
Smart contract contracts/src/AuraSciEscrow.sol Solidity 0.8.24 + OZ
DB schema backend/prisma/schema.prisma Postgres via Prisma

🔐 How money moves

The contract supports four ways to move USDC. Three of them require an EIP-712 signature from the backend's verifier key:

Function Caller What it does
deposit(intentId, amount) Anyone (patrons) Tags USDC against an intentId; emits Deposited.
release(intentId, to, amount, nonce, reason, sig) Scientist Pays a milestone tranche to the scientist after the AI verifier signs. Contract checks sig recovers to signer.
refund(intentId, patron, amount, nonce, reason, sig) Patron Claws back a deposit when intent or milestone is rejected. Same signature check.
adminWithdraw(intentId, to, amount, reason) Admin only Escape hatch / governance — bypasses milestone gating, capped at 100k USDC per tx.

Admin power is rotatable via a two-step transferAdminacceptAdmin flow. The signer is immutable (set once at deploy) — rotating the verifier key means deploying a fresh escrow pointed at the new signer address (which is how the Privy server wallet became the signer).

Why signatures and not direct admin calls? So the AI worker can sign release authorizations without ever holding withdraw power. If the verifier key leaks, the worst case is forged milestone releases — admin can rotate the key and pause via setPaused. The admin key itself stays cold.

The reason field on every milestone release() carries the SHA-256 of the proof artifact stored on Walrus — so each on-chain Released event is a permanent commitment to exactly the bytes the AI verifier graded. Fetch the blob from any Walrus aggregator, hash it, compare with the event: the whole release trail is independently auditable.


🐋 Walrus storage

Proof artifacts live on Walrus — decentralized blob storage certified on Sui, chain-agnostic by design (our money rail stays on Base). Three integration points:

Path Direction What happens
submit-proof write Scientist's proof file → PUT {publisher}/v1/blobs → blobId + SHA-256 recorded on the Milestone row
scoreProof read In llm mode the verifier fetches the blob back from an aggregator, extracts content (PDF/text), and grades it — the release signature only exists because Walrus returned the artifact
Frontend read "Proof on Walrus ↗" links on milestone cards resolve via the public aggregator; the on-chain reason anchors the same bytes

Client: backend/src/lib/walrus.ts (~100 lines, plain fetch, no SDK). Generic media uploads go through POST /api/storage-upload (backend/src/routes/storage.ts). The public testnet publisher/aggregator are the zero-config defaults — see docs/WALRUS_INTEGRATION.md for the full write-up, demo script and design notes.


🧠 AI gatekeeper & verifier

Two distinct AI jobs, both run by the same worker process (backend/src/ai-worker.ts):

Gatekeeper (at publish time, backend/src/lib/ai.ts)

  • 5-agent quorum, each scoring 0–100 from a different angle (feasibility, milestone clarity, scientific rigor, novelty, risk).
  • Pass requires BOTH ≥3/5 agents approving AND mean score ≥ 70. Otherwise → status = "rejected" and the intent is hidden from the market.

Both jobs call Anthropic Claude via the official @anthropic-ai/sdk (backend/src/lib/ai.ts callClaude). Model is set by ANTHROPIC_MODEL (default claude-haiku-4-5 — cheap enough to grade every claim; bump to claude-sonnet-4-6 / claude-opus-4-8 for more rigor).

Verifier (per-milestone proof)

  • In llm mode (set AI_VERIFIER_MODE=llm + ANTHROPIC_API_KEY) the worker fetches the proof artifact back from Walrus, extracts readable content (PDF via unpdf, text formats directly), and grades it against the milestone's stated deliverable. A proof that can't be retrieved never produces a release signature. approve mode remains as a zero-key demo escape hatch.
  • Verified live: a real milestone proof scores 82/100 and a garbage proof 5/100npm run --prefix backend exec tsx scripts/verifier-claude-smoke.mts.
  • On pass, the worker signs an EIP-712 release payload and caches it on the milestone row. The scientist's "Claim" button broadcasts that cached signature — failed broadcasts (cancelled popups, gas issues) become a clean "Resume claim" without re-grading.

The verifier key never touches the frontend. The signed payload + nonce live in Milestone.releaseSignature / releaseNonce.


🔐 Privy server wallet (the AI signer)

The AI verifier is an agent, and its release-signing key is a non-custodial Privy server wallet — not a raw private key in an env var. After the verifier grades a proof, the backend signs the EIP-712 Release authorization with the server wallet via @privy-io/server-auth (createViemAccount → viem LocalAccount); the escrow's immutable signer is that wallet's address, so its ECDSA check passes.

A policy engine rule governs the wallet: it may only call eth_signTypedData_v4 on Base Sepolia (chain_id == 84532). It can never send a transaction, sign another chain's data, or export its key — so even a fully-compromised backend can't make the agent move funds, only sign valid milestone releases the escrow already enforces.

  • Switch signer via RELEASE_SIGNER=local|privy; wallet ids in PRIVY_WALLET_ID / PRIVY_WALLET_ADDRESS.
  • Setup: backend/scripts/privy-setup-wallet.mts creates the wallet + policy; privy-sign-test.mts proves a Privy-signed release recovers to the wallet.
  • Optional: setting NEXT_PUBLIC_PRIVY_APP_ID (frontend) + PRIVY_APP_ID/ PRIVY_APP_SECRET (backend) also lights up Privy email / Google / X login alongside the SIWE wallet flow (dual-token auth).

Built for the ETHGlobal Agents · Privy prize (server wallets + policy engine).


🔑 SIWE auth + DB-pinned wallets

Login is Sign-In-With-Ethereum: the browser wallet signs a SIWE message carrying a one-time server nonce, and the backend (backend/src/routes/auth.ts) verifies it and issues a self-signed session JWT whose subject is the wallet address. Every API call carries that JWT; backend/src/lib/auth.ts verifies it and hydrates the local User row.

User.wallet is the user's permanent on-chain identity — the same address that signed in is the only one every downstream check (intent ownership, scientist payout, refund eligibility) accepts.

Frontend mirrors the same rule: useEnsureWalletReady refuses to sign transactions from any address other than /me.wallet.


🚀 Local development

Prerequisites

  • Node 20+
  • Postgres 14+ (local or remote)
  • Base Sepolia RPC URL (Alchemy, Infura, or public endpoint)
  • An Anthropic API key (only needed for real AI scoring in llm mode; the default verifier mode is "approve")

1. Clone + install

git clone https://github.com/evayou0915/Ethglobal.git
cd Ethglobal
npm install
cd backend && npm install && cd ..
cd contracts && npm install && cd ..

2. Configure env

cp .env.example .env.local          # frontend (public NEXT_PUBLIC_* only)
cp backend/.env.example backend/.env # backend (DB url, signer key, JWT secret, Anthropic key)

Critical vars:

  • DATABASE_URL — Postgres connection string
  • JWT_SECRET — session-JWT signing secret (openssl rand -hex 32)
  • SIGNER_PRIVATE_KEY — EIP-712 release signer (a fresh dev key is fine for local)
  • ESCROW_ADDRESS / USDC_ADDRESS — set to your deployed contract + USDC on Base Sepolia
  • NEXT_PUBLIC_CHAIN_ID (84532 for Sepolia)
  • WALRUS_PUBLISHER_URL / WALRUS_AGGREGATOR_URL — default to the public Walrus testnet endpoints; no key needed
  • AI_VERIFIER_MODEllm for real Walrus-fetch + LLM grading (needs ANTHROPIC_API_KEY), approve to demo the flow without one

3. Deploy / use the escrow contract

cd contracts
npm run compile
npm test                                # 17 contract tests should pass
npm run deploy:sepolia                  # outputs the contract address

Copy the address into backend/.env (ESCROW_ADDRESS) and .env.local (NEXT_PUBLIC_ESCROW_ADDRESS).

4. Init DB + run the backend

cd backend
npm run db:migrate:dev                  # apply migrations
npm run db:seed                         # optional demo data
npm run dev                             # api + indexer + ai-worker in parallel

5. Run the frontend

# in the repo root
npm run dev                             # next dev on :5173

Open http://localhost:5173, sign in with your browser wallet (MetaMask / Rabby), grab test USDC from the Circle Sepolia faucet, and fund an intent.


🛠 Repository layout

Ethglobal/
├── src/                          # Next.js frontend
│   ├── app/(app)/               # App Router pages (market, intent, create, scientist, portfolio, leaderboard, ...)
│   ├── client/                  # api.ts, hooks.ts, wagmi config
│   ├── components/              # Nav, WalletPanel, SignInModal, Toast, ...
│   └── types/                   # shared API DTOs
│
├── backend/                      # self-hosted Hono backend
│   ├── src/
│   │   ├── server.ts            # HTTP entry point
│   │   ├── indexer.ts           # on-chain event → DB
│   │   ├── ai-worker.ts         # AiJob queue drainer
│   │   ├── routes/              # /api/intents, /auth, /aura, /admin, /refunds, ...
│   │   └── lib/                 # auth (SIWE JWT), ai (LLM quorum), eip712, db, ...
│   ├── prisma/
│   │   ├── schema.prisma
│   │   └── migrations/
│   └── scripts/                 # one-off ops scripts (purge, simulate-release, ...)
│
├── contracts/                    # Hardhat workspace, decoupled from the Next.js app
│   ├── src/
│   │   ├── AuraSciEscrow.sol
│   │   └── test/MockUSDC.sol
│   ├── test/                    # 17 unit tests
│   └── scripts/deploy.ts
│
├── docs/
│   ├── ARCHITECTURE.md
│   ├── BASE_MIGRATION.md        # design rationale + phase log
│   └── DEPLOYMENT.md
│
└── public/                       # static demo data + landing assets

🚢 Deployment

Tier Where Notes
Frontend Vercel Static + SSR Next.js. NEXT_PUBLIC_* vars only.
Backend (API + indexer + ai-worker) Self-hosted (Render / Fly / EC2 / your VPS) Long-running Node processes. pm2 or docker-compose recommended — Vercel can't run them.
Database Postgres on the backend host (or managed) Single source of truth for off-chain state.
Contract Base Sepolia (testnet) / Base mainnet See docs/DEPLOYMENT.md.

backend/ecosystem.config.cjs is a pm2 config that starts the three Node processes (api / indexer / ai-worker) as one unit.


📊 What's done vs. what's deliberately stubbed

Done

  • Full create → AI gatekeeper → publish → fund → submit-proof → AI verify → release → completed flow
  • Walrus storage end-to-end: proofs stored as blobs at submit time, AI verifier reads them back through the aggregator before signing, on-chain Released.reason anchors the artifact's SHA-256, UI links resolve every proof publicly
  • Patron refund (per-rejected-milestone + full intent rejection)
  • Admin escape hatches: refundAll, adminWithdraw
  • Aura social-points: seasons, boosts, milestone-yield distribution
  • Leaderboard + activity feed (live indexer events)
  • Per-user portfolio with Boost from holdings rows
  • Scientist dashboard with milestone trajectory, dueDate display + Overdue flag
  • DB-pinned wallet enforcement: no more "active wallet drifts under the contract" bugs

Stubbed by design (v1 demo)

  • Verifier default mode is approve — real grading (AI_VERIFIER_MODE=llm) fetches the proof from Walrus and scores it with an LLM; the default stays permissive so the flow demos without an LLM key. Flip the env var for real verification.
  • Scientist "approved" is implicit — any user who completes /onboard is treated as approved; no admin review queue. See src/app/(app)/scientist/page.tsx:44-48.

Not started

  • Automated test coverage for backend + frontend (contract tests do exist)
  • Verifier-key KMS / HSM storage (production-grade key custody)
  • Phase 3 governance (patron-DAO challenges)

📚 Further reading


📄 License

MIT © 2026 AuraSci


AuraSci — Where breakthroughs find believers, and capital follows proof.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages