GitHub - ubiquity/pay.ubq.fi: Generate and claim spender permits (EIP-2612) · GitHub
Skip to content

About

Generate and claim spender permits (EIP-2612)

Resources

Stars

10 stars

Watchers

4 watching

Forks

Repository files navigation

pay.ubq.fi

Permit claiming web app for Ubiquity Rewards.

  • Frontend: React + TypeScript + Vite in src/.
  • Server: serve.ts (Deno Deploy) serves the built SPA from dist/ and exposes a small API to record permit claims in Supabase.

Setup

  1. Install dependencies:
    bun install
  2. Create a .env file:
    cp .env.example .env
  3. Fill in required variables (see .env.example):
    • Backend (serve.ts): SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY
    • Frontend (Vite): VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY
    • CI build convenience: SUPABASE_ANON_KEY is used to set VITE_SUPABASE_ANON_KEY in .github/workflows/deno-deploy.yml

All frontend variables must be prefixed with VITE_ to be exposed to the app. RPC uses /rpc only on *.ubq.fi hostnames; all other hostnames use https://rpc.ubq.fi.

Development

  • Two‑port dev with HMR:

    bun run dev
    • Vite runs on http://localhost:5173
    • serve.ts runs on http://localhost:8000
    • Vite proxies /api/* and top‑level numeric routes to :8000.
  • Production‑like single‑port (no HMR):

    bun run start

    Builds the frontend and serves it + API on http://localhost:8000.

Build

bun run build

Outputs static files to dist/.

Deployment

Deployment is handled by GitHub Actions via .github/workflows/deno-deploy.yml.

  • Builds dist/ with Bun/Vite.
  • Deploys serve.ts to Deno Deploy and includes dist/**.
  • Required Deploy secrets: DENO_DEPLOY_TOKEN, SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY.

API

serve.ts exposes POST /api/permits/record-claim which accepts { "transactionHash": "0x...", "networkId": 100 } and derives the permit signature(s) by decoding Permit2 calldata before updating Supabase.

Note: this endpoint uses SUPABASE_SERVICE_ROLE_KEY (bypasses RLS), so security comes from on-chain transaction verification before writing.

CLI Tools

One-off tooling lives in scripts/ (requires .env with Supabase + RPC vars).

  • Audit permits against both Permit2 contracts (includes “nonce used but DB transaction missing” mismatches):
    • bun run permit2:audit -- --owner 0x... --include-permits --out /tmp/permit2-audit.json
  • Build an invalidation plan (no transactions sent):
    • bun run permit2:invalidate -- --owner 0x... --target old --only-db-unclaimed --out /tmp/permit2-invalidate-plan.json
  • Execute invalidations (sends transactions; use --max-txs as a safety brake):
    • INVALIDATOR_PRIVATE_KEY=0x... bun run permit2:invalidate -- --owner 0x... --target old --only-db-unclaimed --execute --max-txs 50 --out /tmp/permit2-invalidate-executed.json
  • Backfill missing permits.transaction values for claim txs:
    • bun run permit2:backfill -- --owner 0x... --out /tmp/permit2-backfill.json
    • For a more complete one-off backfill on Gnosis, add --match-mode beneficiary --scan-new-permit2-txlist.
    • Add --execute to write to Supabase (use --max-updates as a safety brake).
  • Seed small test permits for QA (default: 1e18 UUSD on Gnosis; plan-only unless --execute):
    • INVALIDATOR_PRIVATE_KEY=0x... bun run permit2:seed-test-permits -- --beneficiary 0x... --beneficiary-user-id <githubUserId> --execute --out /tmp/test-permits.json
  • Sign/broadcast test permit claims (sign-only unless --execute):
    • BENEFICIARY_PRIVATE_KEY=0x... bun run permit2:claim-test-permits -- --beneficiary 0x... --limit 10 --execute --batch --out /tmp/test-claims.json

Formatting

bun run format / bun run format:check run Prettier across the repo (including serve.ts).

Contracts

Permit2 and PermitAggregator addresses used by the UI are in src/constants/config.ts.

Cloudflare Workers deployment (2026-10-12)

worker/entry.ts + wrangler.toml serve the Vite dist/ bundle from Cloudflare Workers with the previous serve.ts routing (files, SPA fallback, POST /api/permits/record-claim).

Deployed now: https://pay-ubq-fi.ubq.workers.dev (verified root, assets, SPA route, and the claim endpoint's validation paths). The claim handler from serve.ts is ported into the worker (RPC checks, Permit2 decode via viem, Supabase REST read/update) and covered by worker/entry_test.ts (bun test worker/entry_test.ts).

pay.ubq.fi is cut over to the worker (zone route pay.ubq.fi/*), so the UI, assets, and SPA routing are live. SUPABASE_URL is set as a Worker secret; the claim endpoint still answers {"error":"Supabase not configured"} until SUPABASE_SERVICE_ROLE_KEY is supplied.

The anon key cannot substitute: a targeted no-op update against the unclaimed row proved RLS filters anonymous UPDATEs (0 rows touched), so recording claims genuinely requires the service-role key. Build with VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY set (org-level Supabase values).

About

Generate and claim spender permits (EIP-2612)

Resources

Stars

10 stars

Watchers

4 watching

Forks

Used by

Contributors

Languages