cosign-demo is a standalone Nitrolite example app for shared approvals. Two participants create a cart, co-sign checkout actions, move funds between their Shared Wallet and the checkout cart, and close the cart when they are done.
If you are building with this example, start with:
- this README
docs/architecture/overview.mddocs/architecture/feature-map.mdAGENTS.mdif you are using Claude Code or another coding agent
The app presents two related balance layers:
- Shared Wallet: each participant's Nitrolite balance for the room asset
- Checkout Cart: a shared Nitrolite app session for this cart only
Typical flow:
- Create a shared cart with a friend.
- Start Shared Checkout and have both participants approve it.
- Add funds into Shared Wallet if needed.
- Move funds from Shared Wallet into the checkout cart.
- Propose a purchase and have both participants approve it.
- Finish Checkout to close the cart and return the final split to Shared Wallet balances.
- Withdraw from Shared Wallet back to the on-chain wallet if desired.
Important behavior:
- Shared Wallet actions work even when there is no active cart.
Withdraw To Walletmoves funds from Shared Wallet back on-chain.Propose Purchasecurrently reallocates funds inside the checkout session. It does not pay an external merchant.Finish Checkoutcloses the checkout session and returns the final split to Shared Wallet balances.- Smooth approvals via session keys are supported to reduce repeat approval friction.
- The demo currently uses YUSD and YELLOW on Ethereum Sepolia.
Current reality:
src/components/CosignDemoApp.tsxstill acts as the main application brain.- API routes under
src/app/apihandle rooms, proposals, signatures, submission, health, and expiration. - Integration helpers live under
src/lib. - The repo is standalone and vendors the SDK tarballs it was tested against under
vendor/.
Read next:
Repo-specific agent assets are checked in:
These are part of the repo contract. If architecture, contributor workflow, or runtime expectations change, update them with the code.
.mcp.json preconfigures Next.js devtools MCP. The repo is currently on Next.js 15.5.9.
If you use Claude Code in this repo, start with these skills:
| Command | When to use |
|---|---|
/trace-checkout-flow |
Before editing a flow; traces the path from UI action through API, SDK, and state |
/wallet-channel-debug |
When deposits, withdrawals, channel actions, or checkout/session actions fail |
/extract-feature-slice |
When pulling a bounded concern out of src/components/CosignDemoApp.tsx |
/proposal-contract-change |
Before changing proposal payloads, signing paths, or app-session-related contracts |
Run these inside a Claude Code session opened at the repo root.
Implemented today:
realUses Supabase, the Yellow sandbox Clearnode, and Sepolia RPCs.
- Node.js 20+
- npm 10+
- A Supabase project with the schema from
supabase/schema.sql - A reachable Clearnode websocket endpoint
- Ethereum Sepolia RPC access
git clone <your-fork-or-org-repo-url>
cd cosign-demo
npm install
cp .env.example .env.localPopulate .env.local with:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYNEXT_PUBLIC_CLEARNODE_WS_URLNEXT_PUBLIC_BLOCKCHAIN_RPCSSUPABASE_SERVICE_ROLE_KEYCRON_SECRET
Then run:
npm run devnpm run typecheck
npm run buildRun validation sequentially, not in parallel. npm run build assumes the required environment variables from .env.example are populated, and the build script clears .next first to avoid stale route-artifact failures while the repo still relies on generated .next/types.
Apply supabase/schema.sql to your project before running the app. The demo expects:
roomsproposalsevents
The API routes use the service role key for privileged server-side actions, including proposal state updates and expiration cleanup.
This repository includes a safe row-clear utility that preserves the schema:
npm run supabase:clear
npm run supabase:clear -- --yes- Push this repository to the target GitHub org.
- Import the repo into Vercel.
- Set the required environment variables for Preview and Production.
- Ensure the deployment can reach your Clearnode websocket and Sepolia RPC provider.
- Keep
vercel.jsonenabled so Vercel invokes/api/proposals/expire. - Set
CRON_SECRETin Vercel and ensure the API route validates the same secret.
| Variable | Used by | Notes |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Browser + server | Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Browser + server | Public anon key |
NEXT_PUBLIC_CLEARNODE_WS_URL |
Browser | Clearnode websocket endpoint |
NEXT_PUBLIC_BLOCKCHAIN_RPCS |
Browser | chainId:https://rpc pairs |
SUPABASE_SERVICE_ROLE_KEY |
API routes | Required for server writes |
CRON_SECRET |
Vercel cron | Required by /api/proposals/expire |
This repository intentionally vendors the SDK tarballs instead of consuming npm releases directly. That is a temporary packaging strategy until the tested SDK state is published.
See vendor/README.md for package provenance.
The scripts/ directory contains helpers for local diagnosis and operator workflows:
npm run node:checknpm run node:diag:validatorsnpm run channel:repair:voidnpm run vault:depositnpm run supabase:clear
These are optional for normal app usage, but useful when debugging node connectivity, validator support, or stuck channels.
Check that:
- the cart was created against the same Clearnode configured in
NEXT_PUBLIC_CLEARNODE_WS_URL - both participants are connected to the same room and asset
- the vendored SDK tarballs still match the tested Nitrolite state
Check:
- the selected asset and chain match the configured environment
- whether the failing path goes through compat or a direct inner SDK call
- whether live node state and local UI state are aligned
Use docs/architecture/feature-map.md and .claude/skills/wallet-channel-debug/SKILL.md as the first debugging entrypoints.