diff --git a/.env.example b/.env.example index 9983ad0..f5eef2c 100644 --- a/.env.example +++ b/.env.example @@ -7,7 +7,7 @@ SUPABASE_SERVICE_ROLE_KEY= CIRCLE_API_KEY= CIRCLE_ENTITY_SECRET= CIRCLE_BLOCKCHAIN=ARC-TESTNET -CIRCLE_USDC_TOKEN_ID= +CIRCLE_USDC_TOKEN_ID=15dc2b5d-0994-58b0-bf8c-3a0501148ee8 # Misc ADMIN_EMAIL=admin@admin.com diff --git a/README.md b/README.md index 8c53397..a2a1ea4 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,119 @@ # Arc Commerce -This project demonstrates how to integrate USDC as a payment method for purchasing credits on Arc. +Integrate USDC as a payment method for purchasing credits on Arc. This sample application uses Next.js, Supabase, and Circle Developer Controlled Wallets to demonstrate a credit purchase flow with USDC payments on Arc testnet. -## Table of Contents +User dashboard for credit purchase -- [Clone and Run Locally](#clone-and-run-locally) -- [Environment Variables](#environment-variables) +## Prerequisites -## Clone and Run Locally +- Node.js 20.x or newer +- npm (automatically installed when Node.js is installed) +- Docker (for running Supabase locally) +- [ngrok](https://ngrok.com/) (for local webhook testing) +- Circle Developer Controlled Wallets [API key](https://console.circle.com/signin) and [Entity Secret](https://developers.circle.com/wallets/dev-controlled/register-entity-secret) -1. **Clone and install dependencies:** +## Getting Started + +1. Clone the repository and install dependencies: ```bash git clone git@github.com:circlefin/arc-commerce.git - cd top-up + cd arc-commerce npm install ``` -2. **Set up environment variables:** +2. Create a `.env.local` file in the project root: ```bash cp .env.example .env.local ``` - Then edit `.env.local` and fill in all required values (see [Environment Variables](#environment-variables) section below). + Required variables: + + ```bash + # Supabase + NEXT_PUBLIC_SUPABASE_URL=your_supabase_url + NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY=your_anon_key + SUPABASE_SERVICE_ROLE_KEY=your_service_role_key + + # Circle + CIRCLE_API_KEY=your_circle_api_key + CIRCLE_ENTITY_SECRET=your_entity_secret + CIRCLE_BLOCKCHAIN=ARC-TESTNET + CIRCLE_USDC_TOKEN_ID=15dc2b5d-0994-58b0-bf8c-3a0501148ee8 + + # Misc + ADMIN_EMAIL=admin@admin.com + ``` -3. **Start Supabase locally** (requires Docker): +3. Start Supabase locally: ```bash npx supabase start npx supabase migration up ``` -4. **Start the development server:** +4. Start the development server: ```bash npm run dev ``` - The app will be available at [http://localhost:3000](http://localhost:3000/). The admin wallet will be automatically created on first startup. + The app will be available at `http://localhost:3000`. The admin wallet is automatically created on first startup. -5. **Set up Circle Webhooks:** +5. Set up Circle Webhooks (for local development): - In a separate terminal, start ngrok to expose your local server: + In a separate terminal, expose your local server: ```bash ngrok http 3000 ``` - Copy the HTTPS URL from ngrok (e.g., `https://your-ngrok-url.ngrok.io`) and add it to your Circle Console webhooks section: + Add the webhook endpoint in Circle Console: - Navigate to Circle Console → Webhooks - - Add a new webhook endpoint: `https://your-ngrok-url.ngrok.io/api/circle/webhook` - - Keep ngrok running while developing to receive webhook events + - Add endpoint: `https://your-ngrok-url.ngrok.io/api/circle/webhook` + - Keep ngrok running to receive webhook events + +## How It Works + +- Built with [Next.js](https://nextjs.org/) and [Supabase](https://supabase.com/) +- Uses [Circle Developer Controlled Wallets](https://developers.circle.com/wallets/dev-controlled) for USDC transactions +- Wallet operations handled server-side with `@circle-fin/developer-controlled-wallets` +- Webhook signature verification ensures secure transaction notifications +- Admin wallet automatically initialized on first run ## Environment Variables -Copy `.env.example` to `.env.local` and fill in the required values: +| Variable | Scope | Purpose | +| ------------------------------------- | ----------- | ------------------------------------------------------------------------ | +| `NEXT_PUBLIC_SUPABASE_URL` | Public | Supabase project URL | +| `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY` | Public | Supabase anonymous/public key | +| `SUPABASE_SERVICE_ROLE_KEY` | Server-side | Service role for privileged database operations | +| `CIRCLE_API_KEY` | Server-side | Circle API key for webhook signature verification | +| `CIRCLE_ENTITY_SECRET` | Server-side | Circle entity secret for wallet operations | +| `CIRCLE_BLOCKCHAIN` | Server-side | Blockchain network identifier (e.g., "ARC-TESTNET") | +| `CIRCLE_USDC_TOKEN_ID` | Server-side | USDC token ID for the specified blockchain | +| `ADMIN_EMAIL` | Server-side | Email address that determines which user gets admin dashboard access | -```bash -# Supabase -NEXT_PUBLIC_SUPABASE_URL= -NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY= -SUPABASE_SERVICE_ROLE_KEY= +## Usage Notes -# Circle -CIRCLE_API_KEY= -CIRCLE_ENTITY_SECRET= -CIRCLE_BLOCKCHAIN=ARC-TESTNET -CIRCLE_USDC_TOKEN_ID= +- Designed for Arc testnet only +- Requires valid Circle API credentials and Supabase configuration +- Admin wallet must have sufficient USDC and gas fees +- ngrok (or similar) required for local webhook testing -# Misc -ADMIN_EMAIL=admin@admin.com -``` +## Scripts -| Variable | Scope | Purpose | -| ------------------------------------- | ----------- | ------------------------------------------------------------------------ | -| `NEXT_PUBLIC_SUPABASE_URL` | Public | Supabase project URL. | -| `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY` | Public | Supabase anonymous/public key. | -| `SUPABASE_SERVICE_ROLE_KEY` | Server-side | Service role for privileged writes (e.g., transaction inserts). | -| `CIRCLE_API_KEY` | Server-side | Used to fetch Circle webhook public keys for signature verification. | -| `CIRCLE_ENTITY_SECRET` | Server-side | Circle entity secret for wallet operations. | -| `CIRCLE_BLOCKCHAIN` | Server-side | Blockchain network identifier (e.g., "ARC-TESTNET"). | -| `CIRCLE_USDC_TOKEN_ID` | Server-side | USDC token ID for the specified blockchain. | -| `ADMIN_EMAIL` | Server-side | Admin user email address. | \ No newline at end of file +- `npm run dev`: Start Next.js development server with auto-reload +- `npx supabase start`: Start local Supabase instance +- `npx supabase migration up`: Apply database migrations + +## Security & Usage Model + +This sample application: +- Assumes testnet usage only +- Handles secrets via environment variables +- Verifies webhook signatures for security +- Is not intended for production use without modification + +See `SECURITY.md` for vulnerability reporting guidelines. Please report issues privately via Circle's bug bounty program. \ No newline at end of file diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index 025524b..007fb03 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -36,7 +36,7 @@ export default function ProtectedLayout({
- top-up + arc-commerce
{/* The wallet buttons have been removed from here */} diff --git a/app/layout.tsx b/app/layout.tsx index 00d73b6..e5c3eff 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -29,8 +29,8 @@ const defaultUrl = process.env.VERCEL_URL export const metadata: Metadata = { metadataBase: new URL(defaultUrl), - title: "Next.js and Supabase Starter Kit", - description: "The fastest way to build apps with Next.js and Supabase", + title: "Arc Commerce", + description: "Platform credit purchases using USDC and Circle Wallets", }; export default function RootLayout({ diff --git a/app/page.tsx b/app/page.tsx index 635dc19..36f2c60 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -31,7 +31,7 @@ export default function Home() {
- top-up + arc-commerce
{!hasEnvVars ? : }
diff --git a/package.json b/package.json index 1518e8b..8d0b4ca 100644 --- a/package.json +++ b/package.json @@ -7,13 +7,8 @@ "lint": "next lint" }, "dependencies": { - "@circle-fin/bridge-kit": "^1.1.2", - "@circle-fin/developer-controlled-wallets": "^8.4.1", - "@circle-fin/modular-wallets-core": "^1.0.11", - "@hookform/resolvers": "^5.2.2", - "@metamask/delegation-toolkit": "^0.13.0", + "@circle-fin/developer-controlled-wallets": "^10.0.1", "@radix-ui/react-alert-dialog": "^1.1.15", - "@radix-ui/react-checkbox": "^1.3.1", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-label": "^2.1.7", @@ -27,10 +22,8 @@ "@supabase/supabase-js": "latest", "@tanstack/react-query": "^5.90.2", "@tanstack/react-table": "^8.21.3", - "axios": "^1.12.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "cmdk": "^1.1.1", "date-fns": "^4.1.0", "lucide-react": "^0.511.0", "next": "latest", @@ -38,12 +31,10 @@ "react": "^19.0.0", "react-day-picker": "^9.11.0", "react-dom": "^19.0.0", - "react-hook-form": "^7.63.0", "sonner": "^2.0.7", "tailwind-merge": "^3.3.0", - "viem": "^2.38.0", - "wagmi": "^2.17.5", - "zod": "^4.1.11" + "viem": "^2.44.4", + "wagmi": "^2.19.5" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -51,7 +42,6 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "baseline-browser-mapping": "^2.9.3", "eslint": "^9", "eslint-config-next": "15.3.1", "postcss": "^8", diff --git a/public/screenshot.png b/public/screenshot.png new file mode 100644 index 0000000..f418a1b Binary files /dev/null and b/public/screenshot.png differ