From 27e80911c6c366a43eddf467ea84464d563657ce Mon Sep 17 00:00:00 2001 From: "v.snigerev" Date: Tue, 23 Jun 2026 19:21:14 +0300 Subject: [PATCH] Add x402-insured-settlement solution (agentic x402 insured settlement demo + facilitator-web) --- solutions/x402-insured-settlement/.gitignore | 20 + solutions/x402-insured-settlement/.npmrc | 1 + solutions/x402-insured-settlement/.prettierrc | 6 + solutions/x402-insured-settlement/LICENSE | 21 + solutions/x402-insured-settlement/README.md | 83 + .../x402-insured-settlement/package.json | 31 + .../packages/demo/.gitignore | 7 + .../packages/demo/README.md | 56 + .../demo/app/agents/[id]/edit/page.tsx | 391 ++++ .../packages/demo/app/agents/[id]/page.tsx | 255 +++ .../packages/demo/app/agents/new/page.tsx | 345 ++++ .../packages/demo/app/analytics/page.tsx | 519 +++++ .../demo/app/api/agents/[id]/route.ts | 98 + .../app/api/agents/[id]/withdraw/route.ts | 62 + .../packages/demo/app/api/agents/route.ts | 77 + .../demo/app/api/confidential/reveal/route.ts | 18 + .../packages/demo/app/api/plugins/route.ts | 9 + .../packages/demo/app/api/release/route.ts | 165 ++ .../packages/demo/app/api/resource/route.ts | 275 +++ .../packages/demo/app/api/resources/route.ts | 8 + .../packages/demo/app/api/run/route.ts | 917 +++++++++ .../demo/app/api/session/grant/route.ts | 38 + .../demo/app/api/session/key/route.ts | 22 + .../packages/demo/app/api/session/route.ts | 22 + .../demo/app/api/twokey/state/route.ts | 17 + .../packages/demo/app/components/EChart.tsx | 18 + .../IncidentResponseTheater.module.css | 702 +++++++ .../components/IncidentResponseTheater.tsx | 719 +++++++ .../demo/app/components/SettlementTheater.tsx | 1404 +++++++++++++ .../packages/demo/app/components/Shell.tsx | 40 + .../packages/demo/app/components/Sidebar.tsx | 132 ++ .../demo/app/components/ThemeToggle.tsx | 34 + .../demo/app/components/TreasuryPanel.tsx | 360 ++++ .../app/components/TwoKeyTheater.module.css | 854 ++++++++ .../demo/app/components/TwoKeyTheater.tsx | 665 +++++++ .../demo/app/components/agentTypes.ts | 80 + .../packages/demo/app/globals.css | 1026 ++++++++++ .../demo/app/incident-response/page.tsx | 9 + .../packages/demo/app/layout.tsx | 48 + .../packages/demo/app/page.tsx | 101 + .../packages/demo/app/plugins/page.tsx | 90 + .../packages/demo/app/resources/page.tsx | 83 + .../packages/demo/app/two-key/page.tsx | 16 + .../packages/demo/lib/agentStore.ts | 401 ++++ .../packages/demo/lib/agentWallet.ts | 174 ++ .../packages/demo/lib/confidentialConfig.ts | 52 + .../packages/demo/lib/confidentialCoverage.ts | 61 + .../packages/demo/lib/confidentialEscrow.ts | 75 + .../packages/demo/lib/coverage.ts | 306 +++ .../packages/demo/lib/incident.ts | 713 +++++++ .../packages/demo/lib/incidentAgent.ts | 151 ++ .../packages/demo/lib/incidentReports.ts | 60 + .../packages/demo/lib/passkeyTreasury.ts | 174 ++ .../packages/demo/lib/pluginCatalog.ts | 140 ++ .../packages/demo/lib/resources.ts | 46 + .../packages/demo/lib/sellerAgent.ts | 109 ++ .../packages/demo/lib/sellerEscrow.ts | 373 ++++ .../packages/demo/lib/sessionStore.ts | 85 + .../packages/demo/lib/sessionWallet.ts | 155 ++ .../packages/demo/lib/store/docStore.ts | 103 + .../packages/demo/lib/tenant-cookie.ts | 1 + .../packages/demo/lib/tenant.ts | 20 + .../packages/demo/lib/twoKey.ts | 625 ++++++ .../packages/demo/lib/zerodev.ts | 20 + .../packages/demo/middleware.ts | 32 + .../packages/demo/next-env.d.ts | 6 + .../packages/demo/next.config.ts | 8 + .../packages/demo/package.json | 38 + .../packages/demo/public/apple-touch-icon.png | Bin 0 -> 8471 bytes .../packages/demo/public/favicon-16x16.png | Bin 0 -> 610 bytes .../packages/demo/public/favicon-192x192.png | Bin 0 -> 9258 bytes .../packages/demo/public/favicon-32x32.png | Bin 0 -> 1301 bytes .../packages/demo/public/favicon-48x48.png | Bin 0 -> 1986 bytes .../packages/demo/public/favicon-512x512.png | Bin 0 -> 19374 bytes .../packages/demo/public/favicon.ico | Bin 0 -> 1986 bytes .../demo/public/logos/reineira-logo.png | Bin 0 -> 517866 bytes .../packages/demo/scripts/agent-client.ts | 32 + .../scripts/confidential-data-buy-e2e.mts | 51 + .../demo/scripts/confidential-probe.mts | 39 + .../packages/demo/scripts/e2e-escrow.mts | 141 ++ .../packages/demo/scripts/insurance-check.mts | 146 ++ .../demo/scripts/stake-confidential-pool.mts | 64 + .../packages/demo/scripts/twokey-proof.ts | 460 +++++ .../packages/demo/tsconfig.json | 30 + .../packages/demo/ui/Callout.tsx | 98 + .../packages/demo/ui/CodeBlock.tsx | 184 ++ .../packages/demo/ui/CopyField.tsx | 130 ++ .../packages/demo/ui/DocsTable.tsx | 64 + .../packages/demo/ui/HonestyRail.tsx | 80 + .../packages/demo/ui/Icon.tsx | 93 + .../packages/demo/ui/PropertyCard.tsx | 107 + .../packages/demo/ui/SiteFooter.tsx | 233 +++ .../packages/demo/ui/Wordmark.tsx | 17 + .../packages/demo/ui/badges.tsx | 165 ++ .../packages/demo/ui/index.ts | 27 + .../packages/demo/ui/tokens.css | 411 ++++ .../packages/demo/ui/types.ts | 59 + .../packages/demo/vercel.json | 6 + .../packages/facilitator-web/.env.example | 9 + .../packages/facilitator-web/.gitignore | 1 + .../packages/facilitator-web/index.ts | 25 + .../packages/facilitator-web/package.json | 19 + .../packages/facilitator-web/tsconfig.json | 8 + .../packages/facilitator-web/vercel.json | 5 + .../x402-insured-settlement/pnpm-lock.yaml | 1737 +++++++++++++++++ .../pnpm-workspace.yaml | 2 + .../x402-insured-settlement/reineira.json | 22 + .../tsconfig.base.json | 17 + 108 files changed, 18254 insertions(+) create mode 100644 solutions/x402-insured-settlement/.gitignore create mode 100644 solutions/x402-insured-settlement/.npmrc create mode 100644 solutions/x402-insured-settlement/.prettierrc create mode 100644 solutions/x402-insured-settlement/LICENSE create mode 100644 solutions/x402-insured-settlement/README.md create mode 100644 solutions/x402-insured-settlement/package.json create mode 100644 solutions/x402-insured-settlement/packages/demo/.gitignore create mode 100644 solutions/x402-insured-settlement/packages/demo/README.md create mode 100644 solutions/x402-insured-settlement/packages/demo/app/agents/[id]/edit/page.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/agents/[id]/page.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/agents/new/page.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/analytics/page.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/agents/[id]/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/agents/[id]/withdraw/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/agents/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/confidential/reveal/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/plugins/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/release/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/resource/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/resources/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/run/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/session/grant/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/session/key/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/session/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/api/twokey/state/route.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/EChart.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/IncidentResponseTheater.module.css create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/IncidentResponseTheater.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/SettlementTheater.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/Shell.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/Sidebar.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/ThemeToggle.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/TreasuryPanel.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/TwoKeyTheater.module.css create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/TwoKeyTheater.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/components/agentTypes.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/app/globals.css create mode 100644 solutions/x402-insured-settlement/packages/demo/app/incident-response/page.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/layout.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/page.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/plugins/page.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/resources/page.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/app/two-key/page.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/agentStore.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/agentWallet.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/confidentialConfig.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/confidentialCoverage.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/confidentialEscrow.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/coverage.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/incident.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/incidentAgent.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/incidentReports.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/passkeyTreasury.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/pluginCatalog.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/resources.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/sellerAgent.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/sellerEscrow.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/sessionStore.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/sessionWallet.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/store/docStore.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/tenant-cookie.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/tenant.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/twoKey.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/lib/zerodev.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/middleware.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/next-env.d.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/next.config.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/package.json create mode 100644 solutions/x402-insured-settlement/packages/demo/public/apple-touch-icon.png create mode 100644 solutions/x402-insured-settlement/packages/demo/public/favicon-16x16.png create mode 100644 solutions/x402-insured-settlement/packages/demo/public/favicon-192x192.png create mode 100644 solutions/x402-insured-settlement/packages/demo/public/favicon-32x32.png create mode 100644 solutions/x402-insured-settlement/packages/demo/public/favicon-48x48.png create mode 100644 solutions/x402-insured-settlement/packages/demo/public/favicon-512x512.png create mode 100644 solutions/x402-insured-settlement/packages/demo/public/favicon.ico create mode 100644 solutions/x402-insured-settlement/packages/demo/public/logos/reineira-logo.png create mode 100644 solutions/x402-insured-settlement/packages/demo/scripts/agent-client.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/scripts/confidential-data-buy-e2e.mts create mode 100644 solutions/x402-insured-settlement/packages/demo/scripts/confidential-probe.mts create mode 100644 solutions/x402-insured-settlement/packages/demo/scripts/e2e-escrow.mts create mode 100644 solutions/x402-insured-settlement/packages/demo/scripts/insurance-check.mts create mode 100644 solutions/x402-insured-settlement/packages/demo/scripts/stake-confidential-pool.mts create mode 100644 solutions/x402-insured-settlement/packages/demo/scripts/twokey-proof.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/tsconfig.json create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/Callout.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/CodeBlock.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/CopyField.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/DocsTable.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/HonestyRail.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/Icon.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/PropertyCard.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/SiteFooter.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/Wordmark.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/badges.tsx create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/index.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/tokens.css create mode 100644 solutions/x402-insured-settlement/packages/demo/ui/types.ts create mode 100644 solutions/x402-insured-settlement/packages/demo/vercel.json create mode 100644 solutions/x402-insured-settlement/packages/facilitator-web/.env.example create mode 100644 solutions/x402-insured-settlement/packages/facilitator-web/.gitignore create mode 100644 solutions/x402-insured-settlement/packages/facilitator-web/index.ts create mode 100644 solutions/x402-insured-settlement/packages/facilitator-web/package.json create mode 100644 solutions/x402-insured-settlement/packages/facilitator-web/tsconfig.json create mode 100644 solutions/x402-insured-settlement/packages/facilitator-web/vercel.json create mode 100644 solutions/x402-insured-settlement/pnpm-lock.yaml create mode 100644 solutions/x402-insured-settlement/pnpm-workspace.yaml create mode 100644 solutions/x402-insured-settlement/reineira.json create mode 100644 solutions/x402-insured-settlement/tsconfig.base.json diff --git a/solutions/x402-insured-settlement/.gitignore b/solutions/x402-insured-settlement/.gitignore new file mode 100644 index 0000000..22cc911 --- /dev/null +++ b/solutions/x402-insured-settlement/.gitignore @@ -0,0 +1,20 @@ +node_modules/ +dist/ +.next/ +.vercel/ +coverage/ +*.tsbuildinfo + +# Secrets — never commit +.env +.env.* +!.env.example + +# Local runtime state (demo agents) — contains private keys +.agent-store.json +.agent-store.json.* +.session-store.json + +# OS +.DS_Store +Thumbs.db diff --git a/solutions/x402-insured-settlement/.npmrc b/solutions/x402-insured-settlement/.npmrc new file mode 100644 index 0000000..d67f374 --- /dev/null +++ b/solutions/x402-insured-settlement/.npmrc @@ -0,0 +1 @@ +node-linker=hoisted diff --git a/solutions/x402-insured-settlement/.prettierrc b/solutions/x402-insured-settlement/.prettierrc new file mode 100644 index 0000000..e256e24 --- /dev/null +++ b/solutions/x402-insured-settlement/.prettierrc @@ -0,0 +1,6 @@ +{ + "printWidth": 100, + "singleQuote": false, + "semi": true, + "trailingComma": "all" +} diff --git a/solutions/x402-insured-settlement/LICENSE b/solutions/x402-insured-settlement/LICENSE new file mode 100644 index 0000000..ed8d7c3 --- /dev/null +++ b/solutions/x402-insured-settlement/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Reineira Labs Limited + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/solutions/x402-insured-settlement/README.md b/solutions/x402-insured-settlement/README.md new file mode 100644 index 0000000..3b81d06 --- /dev/null +++ b/solutions/x402-insured-settlement/README.md @@ -0,0 +1,83 @@ +--- +title: x402 Insured Settlement +slug: x402-insured-settlement +description: Agentic x402 payments settled through on-chain escrow with optional insurance — autonomous buyer and seller agents moving real USDC on Arbitrum Sepolia, built on ReineiraOS. +framework: monorepo +type: dapp +tags: [x402, payments, escrow, insurance, agents, ai, arbitrum, fhe, fhenix, erc4337, rss] +demoUrl: null +image: null +author: ReineiraOS +dateAdded: 2026-06-23 +repoPath: solutions/x402-insured-settlement +--- + +# x402 Insured Settlement + +[![Platform](https://img.shields.io/badge/ReineiraOS-v0.1-blue)](https://reineira.xyz) +[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE) +[![Buildathon](https://img.shields.io/badge/%F0%9F%8F%86%201st%20place-Agentic%20track-FACC15)](https://arbitrum-london.hackquest.io/buildathons/Arbitrum-Open-House-London-Online-Buildathon) + +> 🏆 **1st place — Agentic track**, [Arbitrum Open House London Online Buildathon](https://arbitrum-london.hackquest.io/buildathons/Arbitrum-Open-House-London-Online-Buildathon) (2026) — [announcement](https://x.com/arbitrum/status/2069113449221910953). + +Autonomous AI agents that pay each other for real resources — settled on-chain +through an x402 → escrow rail with optional insurance coverage and claims. A +buyer agent purchases data behind an x402 paywall; a seller agent serves it; the +payment funds an on-chain escrow on Arbitrum Sepolia and releases on delivery. +Built on the published [`@reineira-os/x402-*`](https://github.com/ReineiraOS/x402) +packages. + +## What it does + +- **Agentic x402** — a buyer agent and a seller agent transact over the x402 + payment-required protocol, no human in the loop +- **Escrow-gated settlement** — every `402` opens a real on-chain escrow; funds + release to the seller on delivery, refund the buyer on timeout +- **Optional insurance** — buyers can attach parametric coverage; missed + delivery files a claim against an underwriter pool +- **Confidential rail (FHE)** — the same flow runs against the Fhenix + FHE-encrypted escrow stack, hiding amounts on-chain +- **Two-Key Halt** — a Sentinel / Guardian verdict primitive that can freeze a + rail under attack +- **Settlement Theater** — a live terminal that surfaces every verify / settle / + release step as it happens + +## Packages + +| Package | Stack | Purpose | +| -------------------------- | ----------------------------- | -------------------------------------------------------------- | +| `packages/demo` | Next.js 16, React 19, ZeroDev | Payment-agents dashboard, resource server, Settlement Theater | +| `packages/facilitator-web` | Hono | Deployable x402 facilitator (`/verify` + `/settle`) for Vercel | + +The on-chain protocol (escrow, receivers, resolvers, FHE codec) ships as the +published `@reineira-os/x402-*` packages — this example consumes them, it does +not vendor their source. + +## Setup + +```bash +pnpm install +``` + +Then copy and fill the env files (testnet only — Arbitrum Sepolia): + +```bash +cp packages/demo/.env.example packages/demo/.env.local +cp packages/facilitator-web/.env.example packages/facilitator-web/.env.local +``` + +## Development + +```bash +pnpm dev # demo on http://localhost:3000 +pnpm build # build every package +pnpm typecheck # tsc --noEmit across packages +``` + +The demo calls a facilitator for `/verify` + `/settle`. Run `packages/facilitator-web` +(or any deployment of `@reineira-os/x402-facilitator`) and point the demo at it +via `FACILITATOR_URL`. + +## License + +MIT — see [LICENSE](LICENSE). diff --git a/solutions/x402-insured-settlement/package.json b/solutions/x402-insured-settlement/package.json new file mode 100644 index 0000000..2f709c2 --- /dev/null +++ b/solutions/x402-insured-settlement/package.json @@ -0,0 +1,31 @@ +{ + "name": "@x402-insured-settlement/monorepo", + "version": "0.1.0", + "private": true, + "description": "x402 Insured Settlement — agentic payments with on-chain escrow and optional insurance, built on ReineiraOS", + "reineira": { + "platform": "0.1" + }, + "scripts": { + "dev": "pnpm --filter @x402-insured-settlement/demo run dev", + "dev:demo": "pnpm --filter @x402-insured-settlement/demo run dev", + "build": "pnpm -r run build", + "typecheck": "pnpm -r run typecheck", + "format": "prettier --write '**/*.{ts,tsx,js,jsx,json,md}'", + "format:check": "prettier --check '**/*.{ts,tsx,js,jsx,json,md}'" + }, + "devDependencies": { + "prettier": "^3.4.0" + }, + "packageManager": "pnpm@10.30.3", + "engines": { + "node": ">=20.0.0", + "pnpm": ">=10.0.0" + }, + "license": "MIT", + "pnpm": { + "onlyBuiltDependencies": [ + "esbuild" + ] + } +} diff --git a/solutions/x402-insured-settlement/packages/demo/.gitignore b/solutions/x402-insured-settlement/packages/demo/.gitignore new file mode 100644 index 0000000..abb5941 --- /dev/null +++ b/solutions/x402-insured-settlement/packages/demo/.gitignore @@ -0,0 +1,7 @@ +# Local runtime state — contains private keys, never commit +.agent-store.json +.session-store.json +*.bak +.env* +.next +node_modules diff --git a/solutions/x402-insured-settlement/packages/demo/README.md b/solutions/x402-insured-settlement/packages/demo/README.md new file mode 100644 index 0000000..eda6335 --- /dev/null +++ b/solutions/x402-insured-settlement/packages/demo/README.md @@ -0,0 +1,56 @@ +# Payment agents (demo) + +`@x402-insured-settlement/demo` — a Next.js dashboard for the x402 + RSS +insured-settlement flow, with autonomous buyer and seller agents settling +real on-chain payments on Arbitrum Sepolia. Built on the published +`@reineira-os/x402-*` packages. + +## What it is + +A "Payment agents" dashboard with a passkey-secured treasury and two +autonomous AI agents — a buyer that pays for resources and a seller that +serves them behind an x402 paywall. Payments settle on-chain via our own +x402 → escrow rail, with optional insurance coverage and claims. A +"Settlement Theater" terminal surfaces each step as it happens. + +Sidebar navigation: + +| Route | Page | Shows | +| ------------ | ------------ | ------------------------------------------------------------------ | +| `/` | Agents | Buyer + seller agents, treasury, the Settlement Theater terminal | +| `/analytics` | Analytics | Charts over settlement activity | +| `/plugins` | Plugins | RSS resolver / policy plugins wired into the escrow | +| `/resources` | Resources | The paid-resource catalog the buyer can purchase | +| `/two-key` | Two-Key Halt | A security primitive on x402 rails (Sentinel / Guardian / verdict) | + +## Run + +The demo needs a facilitator running (it does `/verify` + `/settle`) and a +`.env.local` in this directory with the Arbitrum Sepolia + agent keys — copy +`.env.example` and fill it in. + +Start the facilitator (`../facilitator-web`, or any deployment of +`@reineira-os/x402-facilitator`), then from the solution root: + +```bash +pnpm --filter @x402-insured-settlement/demo dev +``` + +Or from this directory: + +```bash +pnpm dev # next dev on http://localhost:3000 +pnpm build # next build +pnpm typecheck # tsc --noEmit +``` + +## Routes + +- `GET /api/resource` — the x402 resource server. + - No `payment-signature` header → `402` with an x402 `payment-required` + body (version 2, scheme `exact`, network `eip155:421614`, USDC asset + from `@reineira-os/x402-shared`). + - With `payment-signature` header → validates the escrow, runs real + facilitator `/verify` + `/settle`, then returns a **live on-chain data + report** (`lib/resources.ts`): current Arbitrum Sepolia block + gas plus + ETH/USD spot, fetched fresh at request time. Nothing is hardcoded. diff --git a/solutions/x402-insured-settlement/packages/demo/app/agents/[id]/edit/page.tsx b/solutions/x402-insured-settlement/packages/demo/app/agents/[id]/edit/page.tsx new file mode 100644 index 0000000..83e65c9 --- /dev/null +++ b/solutions/x402-insured-settlement/packages/demo/app/agents/[id]/edit/page.tsx @@ -0,0 +1,391 @@ +"use client"; + +import { Fragment, useCallback, useEffect, useState } from "react"; +import Link from "next/link"; +import { useParams, useRouter } from "next/navigation"; +import { Icon } from "../../../../ui/Icon"; +import { MaturityStatusBadge } from "../../../../ui/badges"; +import { + formatDeadline, + type ClientAgent, + type PluginManifest, +} from "../../../components/agentTypes"; + +const DEADLINE_PRESETS = [ + { label: "1 min", value: 60 }, + { label: "5 min", value: 300 }, + { label: "15 min", value: 900 }, + { label: "1 hour", value: 3600 }, +]; + +export default function EditAgentPage() { + const params = useParams<{ id: string }>(); + const router = useRouter(); + const id = params.id; + + const [loading, setLoading] = useState(true); + const [notFound, setNotFound] = useState(false); + const [name, setName] = useState(""); + const [prePrompt, setPrePrompt] = useState(""); + const [pluginIds, setPluginIds] = useState([]); + const [deadlineSeconds, setDeadlineSeconds] = useState(300); + const [plugins, setPlugins] = useState([]); + const [saving, setSaving] = useState(false); + const [error, setError] = useState(null); + const [isDefault, setIsDefault] = useState(false); + const [deleting, setDeleting] = useState(false); + const [confirmOpen, setConfirmOpen] = useState(false); + const [nameTouched, setNameTouched] = useState(false); + + useEffect(() => { + let active = true; + (async () => { + try { + const [agentRes, pluginsRes] = await Promise.all([ + fetch(`/api/agents/${id}`, { cache: "no-store" }), + fetch("/api/plugins", { cache: "no-store" }), + ]); + if (!active) return; + if (agentRes.status === 404) { + setNotFound(true); + return; + } + const agentJson = (await agentRes.json()) as { agent?: ClientAgent }; + const pluginsJson = (await pluginsRes.json()) as { plugins?: PluginManifest[] }; + if (!active) return; + if (agentJson.agent) { + setName(agentJson.agent.name); + setPrePrompt(agentJson.agent.prePrompt); + setPluginIds(agentJson.agent.pluginIds); + setDeadlineSeconds(agentJson.agent.deadlineSeconds); + setIsDefault(!!agentJson.agent.isDefault); + } else { + setNotFound(true); + } + setPlugins(pluginsJson.plugins ?? []); + } catch { + if (active) setNotFound(true); + } finally { + if (active) setLoading(false); + } + })(); + return () => { + active = false; + }; + }, [id]); + + const togglePlugin = (pluginId: string) => + setPluginIds((prev) => + prev.includes(pluginId) ? prev.filter((p) => p !== pluginId) : [...prev, pluginId], + ); + + const NAME_MAX = 40; + const PROMPT_MAX = 300; + const DEADLINE_MIN = 10; + const DEADLINE_MAX = 86400; + const trimmedName = name.trim(); + const nameError = + trimmedName.length === 0 + ? "Give the agent a name." + : trimmedName.length > NAME_MAX + ? `Keep the name under ${NAME_MAX} characters.` + : null; + const promptOver = prePrompt.length > PROMPT_MAX; + const deadlineError = + deadlineSeconds < DEADLINE_MIN || deadlineSeconds > DEADLINE_MAX + ? `Pick a release window between ${DEADLINE_MIN}s and ${DEADLINE_MAX / 3600}h.` + : null; + const canSave = !nameError && !promptOver && !deadlineError && pluginIds.length > 0; + + const save = useCallback(async () => { + if (saving || nameError || promptOver || deadlineError || pluginIds.length === 0) return; + setSaving(true); + setError(null); + try { + const res = await fetch(`/api/agents/${id}`, { + method: "PATCH", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + name: name.trim(), + prePrompt: prePrompt.trim(), + pluginIds, + deadlineSeconds, + }), + }); + const json = (await res.json()) as { agent?: ClientAgent; error?: string }; + if (!res.ok || !json.agent) { + throw new Error(json.error ?? `update failed (${res.status})`); + } + router.push(`/agents/${id}`); + } catch (e) { + setError(e instanceof Error ? e.message : String(e)); + setSaving(false); + } + }, [saving, name, prePrompt, pluginIds, deadlineSeconds, id, router]); + + const remove = useCallback(async () => { + if (deleting) return; + setDeleting(true); + setError(null); + const res = await fetch(`/api/agents/${id}`, { method: "DELETE" }); + if (res.ok) { + router.push("/"); + } else { + setDeleting(false); + setConfirmOpen(false); + setError("Delete failed — this agent cannot be deleted."); + } + }, [deleting, id, router]); + + if (loading) { + return ( +
+
+ + ◠ + + loading agent… +
+
+ ); + } + + if (notFound) { + return ( +
+
+

Agent not found.

+ + Back to agents + +
+
+ ); + } + + return ( +
+
+ + {" "} + Back + +

Edit agent

+ treasury access locked +
+ +
+
+

Identity

+

+ Change the name and standing instructions. The agent keeps its treasury access, existing + deals, and spend history. +

+ +