Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/enclave-dashboard/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# All values are optional — unset ones fall back to the current Sepolia
# deployment (see src/lib/chain.ts). Copy to .env(.local) to override.

# Sepolia RPC endpoint. Defaults to a public node; use a dedicated provider
# (Alchemy/Infura) for production to avoid rate limits.
# VITE_SEPOLIA_RPC=https://eth-sepolia.g.alchemy.com/v2/<your-key>

# Contract addresses — point the dashboard at a different deployment.
# VITE_ENCLAVE_ADDRESS=0xB47B267876B60a06138Bc9dfCee7aa3E26907CCB
# VITE_CIPHERNODE_REGISTRY_ADDRESS=0x497Feea9abB72229aab1584c22b5416ff128926B
# VITE_CRISP_PROGRAM_ADDRESS=0xba3B07aBFd0B8cad68aa1E946CC7AF5C1B1c8B5D

# First block to scan from (the Enclave deploy block). Lower = slower initial
# load (more getLogs chunks); set to the actual deploy block of the above.
# VITE_DEPLOY_BLOCK=10697349

# E3 timeout windows (seconds), from the deployment's timeoutConfig. Used to
# decide whether an E3 is still active vs. expired (input close + these windows).
# VITE_COMPUTE_WINDOW=86400
# VITE_DECRYPTION_WINDOW=3600
1 change: 1 addition & 0 deletions packages/enclave-dashboard/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
84 changes: 84 additions & 0 deletions packages/enclave-dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# @enclave-e3/dashboard

Interfold / CRISP public observation dashboard. Two tabs:

- **CRISP** — hero poll card, live 7-stage timeline, expandable history, network pulse footer.
Observational only (no vote CTA).
- **E3 inspector** — deep technical record of one E3: request, committee, keygen rounds, input
window, compute, decryption, publication, fees, on-chain event log.

## Run

```bash
pnpm install
pnpm --filter @enclave-e3/dashboard dev
```

Opens at `http://localhost:5173`.

## On-chain backend (Sepolia)

The dashboard reads live data from the Sepolia deployment of Enclave
(`packages/enclave-contracts/deployed_contracts.json`). ABIs come from the canonical typechain
factories in `@enclave-e3/contracts/types` so they cannot drift from the deployed contracts. The
`E3Stage` enum is mirrored locally in `src/lib/chain.ts` (matching `IEnclave.E3Stage`).

- `Enclave` proxy at `0xB47B267876B60a06138Bc9dfCee7aa3E26907CCB` — `E3Requested`,
`PlaintextOutputPublished`, `RewardsDistributed`, plus `getE3` / `getE3Stage` / `e3Payments` view
functions.
- `CiphernodeRegistryOwnable` at `0x497Feea9abB72229aab1584c22b5416ff128926B` — `CommitteeRequested`
(threshold + seed), `CommitteeFinalized` (members), `CommitteePublished` (joint PK).
- `CRISPProgram` at `0xba3B07aBFd0B8cad68aa1E946CC7AF5C1B1c8B5D` — emits `InputPublished` for every
ballot. (Enclave's own `InputPublished` is declared but never emitted; inputs live on the
program.) A re-vote reuses its Merkle-leaf `index`, so the true ballot count is the number of
**distinct** indexes. Inputs are only observable for CRISP; other programs report
`inputsTracked: false`.

CRISP question text + option labels are off-chain (the program doesn't store them); the mapping
lives in `src/lib/pollMeta.ts`. Unknown E3 ids get a generic "Encrypted poll #N" header with numeric
option labels.

### Configuration

All deployment-specific values are env-overridable (prefix `VITE_`) so the dashboard can point at a
different deployment without code changes. See `.env.example`; unset values fall back to the current
Sepolia deployment defined in `src/lib/chain.ts`:

- `VITE_SEPOLIA_RPC` — RPC endpoint (defaults to a public node; use Alchemy/Infura for production).
- `VITE_ENCLAVE_ADDRESS`, `VITE_CIPHERNODE_REGISTRY_ADDRESS`, `VITE_CRISP_PROGRAM_ADDRESS` —
contracts.
- `VITE_DEPLOY_BLOCK` — first block to scan from (the Enclave deploy block).

The fetchers chunk `getLogs` calls to 9_500 blocks per request so they work against the stricter
free-tier providers.

### Polling

`useCrispPolls`, `useAllE3s`, and `useE3Details` poll every 15 seconds while mounted. When the
chain-derived stage advances, the CRISP tab's stage + pollState reconcile automatically; manual
overrides via the Tweaks panel still work (they're clobbered on the next poll tick).

## Build

```bash
pnpm --filter @enclave-e3/dashboard build # vite build → dist/
pnpm --filter @enclave-e3/dashboard typecheck # tsc --noEmit
pnpm --filter @enclave-e3/dashboard preview # serve dist/
```

## Deploy (Vercel)

This is a separate Vercel **Project** from the CRISP client, both pointing at the same repo.

1. New Project → import this repo → set **Root Directory** to `packages/enclave-dashboard`.
2. `vercel.json` (committed here) drives the rest:
- installs the whole pnpm workspace (`cd ../.. && pnpm install`),
- builds `@enclave-e3/contracts` first (typechain ABIs the dashboard imports), then the
dashboard,
- serves `dist/`,
- `ignoreCommand` skips redeploys when nothing under `packages/enclave-dashboard`,
`packages/enclave-contracts`, or `pnpm-lock.yaml` changed.
3. Optionally set `VITE_SEPOLIA_RPC` in the project's Environment Variables.

The dashboard intentionally has **no dependency on `@enclave-e3/sdk`** (which needs a Rust/Noir
toolchain to build) — only `@enclave-e3/contracts`, which is plain `hardhat compile` + `tsc`.
19 changes: 19 additions & 0 deletions packages/enclave-dashboard/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>CRISP · Interfold</title>

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600&family=Geist+Mono:wght@400;500&display=swap"
/>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
27 changes: 27 additions & 0 deletions packages/enclave-dashboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@enclave-e3/dashboard",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "Interfold / CRISP public observation dashboard",
"license": "LGPL-3.0-only",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@enclave-e3/contracts": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"viem": "^2.21.0"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"typescript": "^5.5.3",
"vite": "^5.4.0"
}
}
Loading
Loading