Skip to content
Draft
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
8 changes: 8 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
node_modules
.next
dist
artifacts
cache
coverage
*.lock
pnpm-lock.yaml
10 changes: 10 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf"
}
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 🚀 CASTQUEST V3 — Autonomous Multi-Chain Creative Economy

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FCastQuest%2Fcast&root-directory=apps/web)

## 📚 Documentation

All documentation lives in the `docs-site/` directory.
Expand Down
31 changes: 31 additions & 0 deletions apps/web/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Required
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_walletconnect_project_id

# Alchemy API Key (for RPC)
NEXT_PUBLIC_ALCHEMY_API_KEY=your_alchemy_api_key

# Chain Configuration (default: 8453 = Base mainnet)
NEXT_PUBLIC_CHAIN_ID=8453

# Contract Addresses (Base Mainnet)
NEXT_PUBLIC_CAST_TOKEN_ADDRESS=0x0000000000000000000000000000000000000000
NEXT_PUBLIC_MARKETPLACE_ADDRESS=0x0000000000000000000000000000000000000000
NEXT_PUBLIC_GOVERNANCE_ADDRESS=0x0000000000000000000000000000000000000000

# Indexer / API
NEXT_PUBLIC_API_URL=https://api.castquest.xyz
NEXT_PUBLIC_GRAPHQL_URL=https://api.castquest.xyz/graphql

# Farcaster (for frame integration)
FARCASTER_APP_FID=
FARCASTER_APP_MNEMONIC=

# Database (server-side only)
DATABASE_URL=postgresql://user:password@localhost:5432/castquest

# OpenAI (for agentic features)
OPENAI_API_KEY=

# Turbo Remote Cache (optional)
TURBO_TOKEN=
TURBO_TEAM=
25 changes: 25 additions & 0 deletions apps/web/__tests__/lib/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { describe, it, expect } from 'vitest';
import { cn } from '../../lib/utils';

describe('cn() utility', () => {
it('combines class names', () => {
expect(cn('foo', 'bar')).toBe('foo bar');
});

it('handles conditional classes', () => {
expect(cn('base', true && 'active', false && 'inactive')).toBe('base active');
});

it('deduplicates Tailwind classes', () => {
const result = cn('text-sm text-lg');
expect(result).toBe('text-lg');
});

it('handles undefined and null', () => {
expect(cn('foo', undefined, null, 'bar')).toBe('foo bar');
});

it('handles object syntax', () => {
expect(cn({ foo: true, bar: false, baz: true })).toBe('foo baz');
});
});
55 changes: 55 additions & 0 deletions apps/web/app/admin/agents/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ShellLayout } from '../../../components/layout/ShellLayout';
import { Card } from '../../../components/ui/Card';

const agents = [
{ id: 'pricing-1', name: 'PricingAgent', status: 'active', tasks: 142, errors: 0 },
{ id: 'monitor-1', name: 'MonitoringAgent', status: 'active', tasks: 89, errors: 1 },
{ id: 'creation-1', name: 'CreationAgent', status: 'idle', tasks: 56, errors: 0 },
{ id: 'auction-1', name: 'AuctionAgent', status: 'active', tasks: 203, errors: 2 },
{ id: 'fraud-1', name: 'FraudAgent', status: 'active', tasks: 31, errors: 0 },
{ id: 'curation-1', name: 'CurationAgent', status: 'idle', tasks: 77, errors: 0 },
];

const statusColor: Record<string, string> = {
active: 'bg-emerald-500',
idle: 'bg-yellow-500',
error: 'bg-red-500',
};

export default function AgentsPage() {
return (
<ShellLayout>
<Card title="Agent Monitoring">
<div className="overflow-x-auto">
<table className="w-full text-xs">
<thead>
<tr className="border-b border-slate-700 text-slate-400 text-left">
<th className="pb-2 pr-4">ID</th>
<th className="pb-2 pr-4">Name</th>
<th className="pb-2 pr-4">Status</th>
<th className="pb-2 pr-4">Tasks</th>
<th className="pb-2">Errors</th>
</tr>
</thead>
<tbody>
{agents.map((agent) => (
<tr key={agent.id} className="border-b border-slate-800 text-slate-300">
<td className="py-2 pr-4 font-mono">{agent.id}</td>
<td className="py-2 pr-4">{agent.name}</td>
<td className="py-2 pr-4">
<span className="flex items-center gap-1">
<span className={`h-2 w-2 rounded-full ${statusColor[agent.status]}`} />
{agent.status}
</span>
</td>
<td className="py-2 pr-4">{agent.tasks}</td>
<td className={`py-2 ${agent.errors > 0 ? 'text-red-400' : ''}`}>{agent.errors}</td>
</tr>
))}
</tbody>
</table>
</div>
</Card>
</ShellLayout>
);
}
41 changes: 41 additions & 0 deletions apps/web/app/admin/audit/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ShellLayout } from '../../../components/layout/ShellLayout';
import { Card } from '../../../components/ui/Card';

const auditLogs = [
{ id: 1, time: '2025-03-13 05:30:12', actor: '0xabc…def', action: 'MarketplaceListing', details: 'Listed GAME token #142' },
{ id: 2, time: '2025-03-13 05:28:44', actor: 'PricingAgent', action: 'PriceUpdate', details: 'CAST/USDC: $0.0412' },
{ id: 3, time: '2025-03-13 05:25:11', actor: '0xfed…123', action: 'GovernanceVote', details: 'Proposal #12 — Yes' },
{ id: 4, time: '2025-03-13 05:20:09', actor: 'FraudAgent', action: 'FlaggedActivity', details: 'Suspicious wallet 0x…' },
{ id: 5, time: '2025-03-13 05:15:33', actor: '0x111…222', action: 'TokenMint', details: 'MEDIA token #203 minted' },
];

export default function AuditPage() {
return (
<ShellLayout>
<Card title="Audit Log">
<div className="overflow-x-auto">
<table className="w-full text-xs">
<thead>
<tr className="border-b border-slate-700 text-slate-400 text-left">
<th className="pb-2 pr-4">Time</th>
<th className="pb-2 pr-4">Actor</th>
<th className="pb-2 pr-4">Action</th>
<th className="pb-2">Details</th>
</tr>
</thead>
<tbody>
{auditLogs.map((log) => (
<tr key={log.id} className="border-b border-slate-800 text-slate-300">
<td className="py-2 pr-4 font-mono text-slate-400">{log.time}</td>
<td className="py-2 pr-4 font-mono">{log.actor}</td>
<td className="py-2 pr-4 text-cyan-400">{log.action}</td>
<td className="py-2 text-slate-400">{log.details}</td>
</tr>
))}
</tbody>
</table>
</div>
</Card>
</ShellLayout>
);
}
55 changes: 55 additions & 0 deletions apps/web/app/admin/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ShellLayout } from '../../../components/layout/ShellLayout';
import { Card } from '../../../components/ui/Card';

export default function SettingsPage() {
return (
<ShellLayout>
<div className="space-y-4 max-w-xl">
<Card title="Protocol Settings">
<div className="space-y-3 text-xs">
<div className="flex justify-between items-center">
<span className="text-slate-300">Protocol Fee</span>
<span className="font-mono text-cyan-400">2.5%</span>
</div>
<div className="flex justify-between items-center">
<span className="text-slate-300">Buyback Rate</span>
<span className="font-mono text-cyan-400">20%</span>
</div>
<div className="flex justify-between items-center">
<span className="text-slate-300">Min Stake</span>
<span className="font-mono text-cyan-400">100 CAST</span>
</div>
<div className="flex justify-between items-center">
<span className="text-slate-300">Governance Quorum</span>
<span className="font-mono text-cyan-400">10%</span>
</div>
</div>
</Card>
<Card title="Network Configuration">
<div className="space-y-3 text-xs">
<div className="flex justify-between items-center">
<span className="text-slate-300">Primary Chain</span>
<span className="font-mono text-cyan-400">Base (8453)</span>
</div>
<div className="flex justify-between items-center">
<span className="text-slate-300">L3 Rollup</span>
<span className="font-mono text-cyan-400">Active</span>
</div>
</div>
</Card>
<Card title="Agent Configuration">
<div className="space-y-3 text-xs">
<div className="flex justify-between items-center">
<span className="text-slate-300">Max Concurrent Agents</span>
<span className="font-mono text-cyan-400">10</span>
</div>
<div className="flex justify-between items-center">
<span className="text-slate-300">Agent Timeout</span>
<span className="font-mono text-cyan-400">30s</span>
</div>
</div>
</Card>
</div>
</ShellLayout>
);
}
50 changes: 50 additions & 0 deletions apps/web/app/admin/treasury/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ShellLayout } from '../../../components/layout/ShellLayout';
import { Card } from '../../../components/ui/Card';

export default function TreasuryPage() {
const metrics = [
{ label: 'Total Value Locked', value: '$2.4M', change: '+12.3%' },
{ label: 'Protocol Revenue (7d)', value: '$48.2K', change: '+5.1%' },
{ label: 'CAST Buybacks (7d)', value: '$12.8K', change: '+8.7%' },
{ label: 'Yield Generated (7d)', value: '$3.2K', change: '+2.4%' },
];

return (
<ShellLayout>
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4 lg:grid-cols-4">
{metrics.map((m) => (
<Card key={m.label}>
<p className="text-[10px] text-slate-400">{m.label}</p>
<p className="text-xl font-bold text-slate-100 mt-1">{m.value}</p>
<p className="text-[10px] text-emerald-400 mt-0.5">{m.change}</p>
</Card>
))}
</div>
<Card title="Treasury Allocation">
<div className="space-y-2">
{[
{ label: 'Liquidity Pools', pct: 45 },
{ label: 'CAST Buybacks', pct: 25 },
{ label: 'Development Fund', pct: 20 },
{ label: 'Community Grants', pct: 10 },
].map((item) => (
<div key={item.label}>
<div className="flex justify-between text-[11px] mb-1">
<span className="text-slate-300">{item.label}</span>
<span className="text-slate-400">{item.pct}%</span>
</div>
<div className="h-1.5 bg-slate-700 rounded-full">
<div
className="h-1.5 bg-cyan-500 rounded-full"
style={{ width: `${item.pct}%` }}
/>
</div>
</div>
))}
</div>
</Card>
</div>
</ShellLayout>
);
}
21 changes: 17 additions & 4 deletions apps/web/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import './globals.css';
import type { ReactNode } from 'react';
import type { Metadata, Viewport } from 'next';

export const metadata = {
title: 'CASTQUEST V3',
description: 'Autonomous multi-chain creative economy'
export const metadata: Metadata = {
title: 'CastQuest V3',
description: 'Autonomous multi-chain creative economy',
manifest: '/manifest.json',
appleWebApp: {
capable: true,
statusBarStyle: 'black-translucent',
title: 'CastQuest',
},
};

export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
themeColor: '#22d3ee',
};

export default function RootLayout({ children }: { children: ReactNode }) {
Expand All @@ -22,7 +35,7 @@ export default function RootLayout({ children }: { children: ReactNode }) {
</div>
</header>
<div className='flex flex-1'>
<aside className='w-60 border-r border-slate-800 bg-slate-950/80'>
<aside className='hidden md:block w-60 border-r border-slate-800 bg-slate-950/80'>
<nav className='p-3 text-sm space-y-1'>
<a href='/dashboard' className='block px-3 py-2 rounded-md bg-slate-800 text-slate-100'>
Dashboard
Expand Down
16 changes: 16 additions & 0 deletions apps/web/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
7 changes: 3 additions & 4 deletions apps/web/components/flows/BuilderToProtocolMap.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import React from "react";
import React from "react";
import { Card } from "../ui/Card";

export function BuilderToProtocolMap() {
return (
<Card title="Builder → Protocol Integration Map">
<pre className="whitespace-pre-wrap text-[10px] text-slate-300">
{AI Builder (Code / Frame / Game / UI)
<pre className="whitespace-pre-wrap text-[10px] text-slate-300">{`AI Builder (Code / Frame / Game / UI)
→ SDK (media / fram / game / code)
→ Contracts (MediaToken / FramToken / GameToken / CodeToken)
→ Marketplace (listings, auctions, sponsors)
→ MC + SubDAO + L3
→ Dashboards + agents + social automation}
→ Dashboards + agents + social automation`}
</pre>
</Card>
);
Expand Down
7 changes: 3 additions & 4 deletions apps/web/components/flows/BuybackFlowDiagram.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import React from "react";
import React from "react";
import { Card } from "../ui/Card";

export function BuybackFlowDiagram() {
return (
<Card title="Buyback Flow — V3">
<pre className="whitespace-pre-wrap text-[10px] text-slate-300">
{User Action
<pre className="whitespace-pre-wrap text-[10px] text-slate-300">{`User Action
→ FeeManager (QUEST)
→ BuybackRouter
→ CAST buybacks (multi-chain)
→ Treasury + pools
→ MC update via indexers
→ Dashboards + agents}
→ Dashboards + agents`}
</pre>
</Card>
);
Expand Down
Loading