1<!DOCTYPE html><!--J85DJ4d2_pu0tm2EaWtIp--><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" as="image" href="/siwa-flow.png"/><link rel="stylesheet" href="/_next/static/chunks/43ec3b8db83f7d7e.css?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/7f7d21b762b07143.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7"/>
1<script src="/_next/static/chunks/f880dec594879f64.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/ae750b60a60fe50a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/8b72cfc40036c827.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/turbopack-9e29effca3a14174.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<script src="/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" async=""></script>
1<meta name="next-size-adjust" content=""/><title>Docs â SIWA</title><meta name="description" content="Documentation for SIWA (Sign In With Agent) â getting started, API reference, wallet integration, and contract addresses."/><meta property="og:title" content="SIWA â Sign In With Agent"/><meta property="og:description" content="Trustless identity and authentication for AI agents. An open standard built on ERC-8004 and ERC-8128."/><meta property="og:image" content="https://siwa.id/og.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="SIWA â Sign In With Agent"/><meta property="og:type" content="website"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:title" content="SIWA â Sign In With Agent"/><meta name="twitter:description" content="Trustless identity and authentication for AI agents. An open standard built on ERC-8004 and ERC-8128."/><meta name="twitter:image" content="https://siwa.id/og.png"/><link rel="icon" href="/favicon.ico?favicon.4c82eb06.ico" sizes="32x32" type="image/x-icon"/>
1<script src="/_next/static/chunks/a6dad97d9634a72d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" noModule=""></script>
1</head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased font-sans"><div hidden=""><!--$--><!--/$--></div><nav class="fixed top-0 left-0 right-0 z-50 border-b border-border bg-background/80 backdrop-blur-sm"><div class="mx-auto flex h-14 max-w-5xl items-center justify-between px-6"><a class="font-mono text-sm font-semibold tracking-tight text-foreground hover:text-accent transition-colors duration-200" href="/">Sign-in with Agent</a><div class="hidden md:flex items-center gap-6"><a class="text-sm text-muted hover:text-foreground transition-colors duration-200 cursor-pointer" href="/docs">Docs</a><a class="text-sm text-muted hover:text-foreground transition-colors duration-200 cursor-pointer" href="/docs/endpoints">Endpoints</a><a href="https://github.com/builders-garden/siwa" target="_blank" rel="noopener noreferrer" class="text-sm text-muted hover:text-foreground transition-colors duration-200 cursor-pointer">GitHub</a><a href="https://8004.org" target="_blank" rel="noopener noreferrer" class="text-sm text-muted hover:text-foreground transition-colors duration-200 cursor-pointer">ERC-8004</a></div><button class="md:hidden flex flex-col justify-center items-center w-8 h-8 gap-1.5 cursor-pointer" aria-label="Toggle menu"><span class="block h-px w-5 bg-muted transition-all duration-200 "></span><span class="block h-px w-5 bg-muted transition-all duration-200 "></span></button></div></nav><main class="pt-14"><div class="mx-auto flex max-w-6xl px-6 py-12"><aside class="hidden md:block w-56 shrink-0 sticky top-20 h-fit max-h-[calc(100vh-6rem)] overflow-y-auto"><nav class="space-y-4"><div><a href="#getting-started" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Getting Started</a></div><div><a href="#architecture" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">How It Works</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-1"><a href="#auth-flow" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Auth Flow</a></div></div></div><div><a href="#signing" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Signing (Agent-Side)</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Agentic Wallets</span><div class="space-y-1"><a href="#wallet-bankr" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Bankr</a><a href="#wallet-circle" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Circle</a><a href="#wallet-openfort" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Openfort</a><a href="#wallet-privy" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Privy</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Other Signers</span><div class="space-y-1"><a href="#wallet-privatekey" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Private Key</a><a href="#wallet-keyring" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Keyring Proxy</a><a href="#smart-accounts" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Smart Accounts</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Sign & Send</span><div class="space-y-1"><a href="#signing-siwa" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">SIWA Sign-In</a><a href="#signing-erc8128" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">ERC-8128 Request Signing</a></div></div></div></div><div><a href="#verification" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Verification (Server-Side)</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Verify</span><div class="space-y-1"><a href="#verify-siwa" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">SIWA Verification</a><a href="#verify-erc8128" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">ERC-8128 Request Verification</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Auth State</span><div class="space-y-1"><a href="#verify-receipts" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Receipts</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Server Middleware</span><div class="space-y-1"><a href="#verify-wrappers-next" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Next.js</a><a href="#verify-wrappers-express" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Express</a><a href="#verify-wrappers-hono" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Hono</a><a href="#verify-wrappers-fastify" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Fastify</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Nonce Store</span><div class="space-y-1"><a href="#nonce-why" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">
1Why Nonces</a><a href="#nonce-memory" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Memory</a><a href="#nonce-redis" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Redis</a><a href="#nonce-kv" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Cloudflare KV</a><a href="#nonce-database" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Database</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Captcha</span><div class="space-y-1"><a href="#captcha-how" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">How It Works</a><a href="#captcha-signin" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Sign-In Captcha</a><a href="#captcha-perrequest" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Per-Request Captcha</a><a href="#captcha-difficulty" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Difficulty Levels</a></div></div></div></div><div><a href="#x402" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">x402 Payments</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Server</span><div class="space-y-1"><a href="#x402-overview" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Overview</a><a href="#x402-server" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Server Setup</a><a href="#x402-sessions" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Sessions</a><a href="#x402-config" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Config Reference</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Middleware</span><div class="space-y-1"><a href="#x402-express" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Express</a><a href="#x402-next" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Next.js</a><a href="#x402-hono" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Hono</a><a href="#x402-fastify" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Fastify</a></div></div><div class="mt-2 first:mt-0"><span class="block text-[10px] font-mono font-medium text-dim/60 uppercase tracking-wider mb-1">Agent</span><div class="space-y-1"><a href="#x402-agent" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Agent-Side</a></div></div></div></div><div><a href="#identity" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Identity & Registry</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-1"><a href="#identity-file" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Identity File</a></div><div class="mt-1"><a href="#identity-registry" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Onchain Registry</a></div></div></div><div><a href="#protocol" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Protocol Spec</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-1"><a href="#protocol-message" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Message Format</a></div><div class="mt-1"><a href="#protocol-fields" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Field Definitions</a></div><div class="mt-1"><a href="#protocol-vs-siwe" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">SIWA vs SIWE</a></div></div></div><div><a href="#contracts" class="block font-mono text-xs font-semibold transition-colors duration-200 cursor-pointer text-foreground hover:text-accent">Contracts</a><div class="mt-1.5 ml-2 border-l border-border pl-3"><div class="mt-1"><a href="#contracts-mainnet" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Mainnet</a></div><div class="mt-1"><a href="#contracts-testnet" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Testnets</a></div><div class="mt-1"><a href="#contracts-format" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Registry Format</a></div><div class="mt-1"><a href="#contracts-rpc" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">RPC Endpoints</a></div><div class="mt-1"><a href="#contracts-explorer" class="block text-xs transition-colors duration-200 cursor-pointer text-dim hover:text-muted">Explorer</a></div></div></div></nav></aside><article class="min-w-0 flex-1 pl-0 md:pl-12"><div class="mb-6 rounded-lg bg-yellow-500/10 border border-yellow-500/30 px-5 py-3"><p class="text-sm font-mono text-yellow-400">This project is a work in progress. Use at your own risk â we welcome<!-- --> <a href="https://github.com/builders-garden/siwa" target="_blank" rel="noopener noreferrer" class="underline underline-offset-2 hover:text-yellow-300 transition-colors duration-200">feedback and contributions</a>.</p></div><h1 class="font-mono text-2xl font-bold text-foreground mb-2">SIWA Documentation</h1><p class="text-sm text-dim mb-8">Sign In With Agent â v1.0</p><div class="mb-12 rounded-lg border border-accent/30 bg-accent/5 px-5 py-4"><p class="text-sm text-muted leading-relaxed"><span class="font-mono font-semibold text-accent">What is SIWA?</span> <!-- -->SIWA (Sign In With Agent) helps AI agents authenticate with services using their<!-- --> <a href="https://8004.org" target="_blank" rel="noopener noreferrer" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">ERC-8004</a> <!-- -->onchain identity. Like SIWE (Sign In With Ethereum) for humans, but for agents with verifiable registration.</p><p class="text-sm text-muted leading-relaxed mt-3"><span class="font-mono font-semibold text-accent">For AI agents:</span> <!-- -->Read<!-- --> <a href="https://siwa.id/skill.md" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200 cursor-pointer">/skill.md</a> <!-- -->
1for structured instructions.</p></div><section id="getting-started" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Getting Started</h2><p class="text-sm leading-relaxed text-muted mb-4">SIWA provides two core capabilities:</p><ul class="space-y-2 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span><strong class="text-foreground">Agent-side:</strong> Sign SIWA messages to prove ownership of an ERC-8004 identity</span></li><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span><strong class="text-foreground">Server-side:</strong> Verify signatures and check onchain registration with multiple modular criteria</span></li></ul><div><div class="flex border-b border-border mb-6"><button class="px-4 py-2 font-mono text-sm transition-colors duration-200 border-b-2 -mb-px text-accent border-accent">Build Agents (signer side)</button><button class="px-4 py-2 font-mono text-sm transition-colors duration-200 border-b-2 -mb-px text-muted border-transparent hover:text-foreground">Build Apps (verifier side)</button></div><div><p class="text-sm leading-relaxed text-muted mb-4">Agents use SIWA to authenticate with services by signing a structured message that proves ownership of their ERC-8004 identity. The service verifies the signature and checks onchain registration.</p><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">1</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Install the SDK</h4><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">npm install @buildersgarden/siwa</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">2</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Create a Signer</h4><p class="text-sm leading-relaxed text-muted mb-4">Choose any wallet provider. See<!-- --> <a href="#wallets" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">Wallet Options</a> <!-- -->for all options.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createLocalAccountSigner </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/signer"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">
1import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> privateKeyToAccount </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"viem/accounts"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 2</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Example: private key signer</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> account </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">privateKeyToAccount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">PRIVATE_KEY</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(173, 219, 103)">`</span><span class="token template-string string" style="color:rgb(173, 219, 103)">0x</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation builtin" style="color:rgb(130, 170, 255)">string</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(173, 219, 103)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> signer </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createLocalAccountSigner</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">account</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">3</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Request a Nonce</h4><p class="text-sm leading-relaxed text-muted mb-4">Get a nonce from the service you want to authenticate with.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> response </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"https://api.example.com/siwa/nonce"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"POST"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> headers</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string-property property" style="color:rgb(128, 203, 196)">"Content-Type"</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"application/json"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> address</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getAddress</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> issuedAt </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">4</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Sign and Submit</h4><p class="text-sm leading-relaxed text-muted mb-4">Build and sign the SIWA message, then submit it to the service.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
2import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> signSIWAMessage </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 3</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> message</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signature </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">signSIWAMessage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> domain</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"api.example.com"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> uri</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"https://api.example.com/siwa"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> agentId</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">42</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Your ERC-8004 token ID</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> agentRegistry</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> chainId</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">84532</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> issuedAt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 4</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Submit to service</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> verifyResponse </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"https://api.example.com/siwa/verify"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"POST"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> headers</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string-property property" style="color:rgb(128, 203, 196)">"Content-Type"</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"application/json"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> message</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signature </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> receipt </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> verifyResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div><div class="flex gap-4 mb-6"><div class="flex-shrink-0 w-8 h-8 rounded-full bg-accent/10 border border-accent/30 flex items-center justify-center"><span class="font-mono text-sm font-semibold text-accent">5</span></div><div class="flex-1 pt-1"><h4 class="font-mono text-sm font-semibold text-foreground mb-2">Make Authenticated Requests</h4><p class="text-sm leading-relaxed text-muted mb-4">Use the receipt for subsequent API calls with ERC-8128 signatures.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
4import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> signAuthenticatedRequest </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/erc8128"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 5</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> request </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"https://api.example.com/action"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"POST"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> headers</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string-property property" style="color:rgb(128, 203, 196)">"Content-Type"</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"application/json"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> action</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"transfer"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 6</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> signedRequest </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">signAuthenticatedRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> receipt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">84532</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> response </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">signedRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div></div></div></div><div class="mt-8 mb-4 grid gap-3 sm:grid-cols-3"><a href="#wallets" class="rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-xs font-semibold text-foreground mb-1">Wallet Options</h4><p class="text-xs text-dim">Use any wallet: Bankr, Circle, Openfort, Privy, private key, or keyring proxy.</p></a><a href="#api" class="rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-xs font-semibold text-foreground mb-1">API Reference</h4><p class="text-xs text-dim">SDK functions, modules, and types.</p></a><a href="#protocol" class="rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-xs font-semibold text-foreground mb-1">Protocol Spec</h4><p class="text-xs text-dim">Message format and authentication flow.</p></a></div></section><section id="architecture" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">How It Works</h2><div id="auth-flow" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Authentication Flow</h3><ol class="space-y-3 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">1.</span><span>The agent requests a <strong class="text-foreground">nonce</strong> from the service, sending its address and agent ID.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">2.</span><span>The service returns the nonce along with timestamps.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">3.</span><span>The agent builds a SIWA message and <strong class="text-foreground">signs it</strong>
6 with its wallet.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">4.</span><span>The agent sends the message and signature to the service.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">5.</span><span>The service <strong class="text-foreground">verifies</strong> the signature and calls the blockchain to confirm the agent owns that identity NFT.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">6.</span><span>If verified, the service returns a <strong class="text-foreground">receipt</strong>. The agent uses this for subsequent authenticated requests.</span></li></ol><p class="text-sm leading-relaxed text-muted mb-4">The SDK provides two main functions:</p><ul class="space-y-2 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span><strong class="text-foreground">Agent-side:</strong> <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">signSIWAMessage(fields, signer)</code> â builds and signs the message</span></li><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span><strong class="text-foreground">Server-side:</strong> <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verifySIWA(message, signature, domain, nonceValid, client, criteria?)</code> â validates signature and checks onchain ownership</span></li></ul><img src="/siwa-flow.png" alt="SIWA authentication flow: Agent requests nonce, signs SIWA message, Service verifies signature and checks onchain ownership, returns HMAC-signed verification receipt, then subsequent API requests use ERC-8128 HTTP signatures" class="w-full rounded-lg border border-border cursor-pointer hover:opacity-90 transition-opacity" width="800" height="730"/></div></section><section id="signing" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Signing (Agent-Side)</h2><p class="text-sm leading-relaxed text-muted mb-4">Everything an agent needs to authenticate: choose a signer, sign SIWA messages for initial sign-in, then sign subsequent API requests with ERC-8128. <br/> SIWA supports both <strong class="text-foreground">EOA</strong> (Externally Owned Account) and <strong class="text-foreground">SCA</strong> (Smart Contract Account) signers â agents backed by smart wallets like Safe, Base Accounts, or ERC-6551 Token Bound Accounts work alongside traditional EOA-based agents.</p><div id="wallet-bankr" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Bankr</h3><p class="text-sm leading-relaxed text-muted mb-4">Bankr's Agent API provides smart contract wallets (ERC-4337) for AI agents with built-in signing capabilities. No additional SDK is needed â the signer communicates directly with the Bankr API over HTTP. Signatures are verified via ERC-1271 automatically.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain"># No extra package needed â only @buildersgarden/siwa</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Create a signer from your Bankr API key:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Bankr Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
6<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from "@buildersgarden/siwa"; 7import { createBankrSiwaSigner } from "@buildersgarden/siwa/signer"; 8<!-- --> 9...</code></pre></div></div><p class="text-sm leading-relaxed text-muted mb-4">Already using Bankr's <a href="https://github.com/BankrBot/openclaw-skills/tree/main/bankr" class="text-accent hover:underline" target="_blank" rel="noopener noreferrer">OpenClaw trading skill</a> for swaps and DeFi? This signer adds SIWA authentication on top â same API key, same wallet.</p></div><div id="wallet-circle" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Circle</h3><p class="text-sm leading-relaxed text-muted mb-4">Circle's developer-controlled wallets provide secure key management for AI agents. Install the Circle SDK alongside SIWA:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">npm install @circle-fin/developer-controlled-wallets</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Create a signer from your Circle wallet credentials:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Circle Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from "@buildersgarden/siwa"; 10import { createCircleSiwaSigner } from "@buildersgarden/siwa/signer"; 11<!-- --> 12...</code></pre></div></div><p class="text-sm leading-relaxed text-muted mb-4">If you already have a Circle client instance, use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createCircleSiwaSignerFromClient</code>:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">From Existing Client</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets"; 13import { createCircleSiwaSignerFromClient } from "@buildersgarden/siwa/signer"; 14<!-- --> 15...</code></pre></div></div></div><div id="wallet-openfort" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Openfort</h3><p class="text-sm leading-relaxed text-muted mb-4">Openfort's backend wallets provide secure key management and account abstraction for AI agents. Install the Openfort Node SDK alongside SIWA:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">
15npm install @openfort/openfort-node</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Create a signer from your Openfort wallet credentials:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Openfort Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from "@buildersgarden/siwa"; 16import { createOpenfortSiwaSigner } from "@buildersgarden/siwa/signer"; 17<!-- --> 18...</code></pre></div></div><p class="text-sm leading-relaxed text-muted mb-4">If you already have an Openfort client instance, use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createOpenfortSiwaSignerFromClient</code>:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">From Existing Client</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import Openfort from "@openfort/openfort-node"; 19import { createOpenfortSiwaSignerFromClient } from "@buildersgarden/siwa/signer"; 20<!-- --> 21...</code></pre></div></div></div><div id="wallet-privy" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Privy</h3><p class="text-sm leading-relaxed text-muted mb-4">Privy's server wallets provide embedded wallet infrastructure for AI agents. Install the Privy Node SDK alongside SIWA:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">npm install @privy-io/node</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Create a signer from your Privy wallet:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Privy Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
21<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { PrivyClient } from "@privy-io/node"; 22import { signSIWAMessage } from "@buildersgarden/siwa"; 23import { createPrivySiwaSigner } from "@buildersgarden/siwa/signer";<!-- --> 24...</code></pre></div></div></div><div id="wallet-privatekey" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Private Key (Backend Scripts)</h3><p class="text-sm leading-relaxed text-muted mb-4">For server-side agents or scripts with direct private key access:</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Private Key Signer Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from "@buildersgarden/siwa"; 25import { createLocalAccountSigner } from "@buildersgarden/siwa/signer"; 26import { privateKeyToAccount } from "viem/accounts";<!-- --> 27...</code></pre></div></div></div><div id="wallet-keyring" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Keyring Proxy (Self-Hosted, Non-Custodial)</h3><p class="text-sm leading-relaxed text-muted mb-4">For AI agents that need secure key isolation, we provide an optional <strong class="text-foreground">keyring proxy</strong> â a separate service that holds the encrypted private key and performs all signing. The agent never touches the key.</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Keyring Proxy Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from "@buildersgarden/siwa"; 28import { createKeyringProxySigner } from "@buildersgarden/siwa/signer"; 29<!-- --> 30...</code></pre></div></div><p class="text-sm leading-relaxed text-muted mb-4">The keyring proxy is completely optional. It's useful when you want:</p><ul class="space-y-2 mb-4 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span>Key isolation from the agent process (protection against prompt injection)</span></li><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span>Optional 2FA via Telegram for transaction approval</span></li><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span>Self-hosted, non-custodial key management</span></li></ul><p class="text-sm leading-relaxed text-muted mb-4">See<!-- --> <a href="/docs/deploy" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">Deploy</a> <!-- -->for keyring proxy setup, architecture, and security model.</p></div><div id="smart-accounts" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Smart Accounts</h3><p class="text-sm leading-relaxed text-muted mb-4">Smart contract wallets (Safe, ZeroDev/Kernel, Coinbase Smart Wallet) work with the same <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createWalletClientSigner</code> â their SDKs expose a standard WalletClient or EIP-1193 provider. The SDK detects the signer type automatically during verification via ERC-1271.</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Smart Account Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
30<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from "@buildersgarden/siwa"; 31import { createWalletClientSigner } from "@buildersgarden/siwa/signer"; 32import { createWalletClient, custom } from "viem";<!-- --> 33...</code></pre></div></div></div><div id="signing-siwa" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">SIWA Sign-In</h3><p class="text-sm leading-relaxed text-muted mb-4">Build and sign a SIWA message to prove ownership of an ERC-8004 identity. The authentication flow consists of two steps:</p><ul class="space-y-2 mb-4 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">1.</span><span><strong class="text-foreground">Get a nonce</strong> from the server's <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/siwa/nonce</code> endpoint</span></li><li class="flex gap-3"><span class="text-accent shrink-0">2.</span><span><strong class="text-foreground">Sign and verify</strong> by sending the signature to <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/siwa/verify</code></span></li></ul><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">signSIWAMessage(fields, signer)</td><td class="py-2 pr-4 text-muted font-mono text-xs">{ message, signature, address }</td><td class="py-2 pr-4 text-muted font-mono text-xs">Build and sign a SIWA message.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">buildSIWAMessage(fields)</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Build a formatted SIWA message string.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa</code>.</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Full Authentication Flow</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signSIWAMessage } from "@buildersgarden/siwa"; 34 35// Step 1: Request nonce from server<!-- --> 36...</code></pre></div></div></div><div id="signing-erc8128" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">ERC-8128 Request Signing</h3><p class="text-sm leading-relaxed text-muted mb-4">After SIWA sign-in, sign every outgoing API request with ERC-8128 HTTP Message Signatures.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">signAuthenticatedRequest(req, receipt, signer, chainId, options?)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Request</td><td class="py-2 pr-4 text-muted font-mono text-xs">Sign outgoing request with ERC-8128.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">createErc8128Signer(signer, chainId, options?)</td><td class="py-2 pr-4 text-muted font-mono text-xs">EthHttpSigner</td><td class="py-2 pr-4 text-muted font-mono text-xs">Create ERC-8128 HTTP signer from SIWA Signer.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/erc8128</code>.</p><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Request Signing Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
36<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { signAuthenticatedRequest } from "@buildersgarden/siwa/erc8128"; 37 38const request = new Request("https://api.example.com/action", {<!-- --> 39...</code></pre></div></div></div></section><section id="verification" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Verification (Server-Side)</h2><p class="text-sm leading-relaxed text-muted mb-4">Everything a service needs to verify agents: validate SIWA sign-in, verify ERC-8128 signed requests, issue receipts, and plug into Express or Next.js.</p><div id="verify-siwa" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">SIWA Verification</h3><p class="text-sm leading-relaxed text-muted mb-4">Verify a signed SIWA message, check onchain ownership, and optionally validate ERC-8004 agent profile criteria. Implement two endpoints:</p><ul class="space-y-2 mb-4 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">1.</span><span><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/siwa/nonce</code> â Issue a nonce for the agent to sign</span></li><li class="flex gap-3"><span class="text-accent shrink-0">2.</span><span><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/siwa/verify</code> â Verify the signed message and issue a receipt</span></li></ul><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">verifySIWA(msg, sig, domain, nonceValid, client, criteria?)</td><td class="py-2 pr-4 text-muted font-mono text-xs">SIWAVerificationResult</td><td class="py-2 pr-4 text-muted font-mono text-xs">Verify signature + onchain ownership + criteria.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">parseSIWAMessage(message)</td><td class="py-2 pr-4 text-muted font-mono text-xs">SIWAMessageFields</td><td class="py-2 pr-4 text-muted font-mono text-xs">Parse SIWA message string to fields.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa</code>. Parameters:</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Parameter</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">message</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">The full SIWA message string.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">signature</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">EIP-191 signature hex string.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">expectedDomain</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Must match message domain.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">nonceValid</td><td class="py-2 pr-4 text-muted font-mono text-xs">function | object</td><td class="py-2 pr-4 text-muted font-mono text-xs">Nonce validator: callback (nonce) => boolean, <!-- -->{ nonceToken, secret }<!-- --> for stateless, or <!-- -->{ nonceStore }<!-- --> for store-based replay protection. See <a href="#nonce-store" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">Nonce Store</a>.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">client</td><td class="py-2 pr-4 text-muted font-mono text-xs">PublicClient</td><td class="py-2 pr-4 text-muted font-mono text-xs">viem PublicClient for onchain verification.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">criteria?</td><td class="py-2 pr-4 text-muted font-mono text-xs">SIWAVerifyCriteria</td><td class="py-2 pr-4 text-muted font-mono text-xs">Optional criteria to filter agents (see below).</td></tr></tbody></table></div><div class="mt-4 mb-4"><h4 class="font-mono text-sm font-semibold text-foreground mb-3">Criteria Options</h4></div><p class="text-sm leading-relaxed text-muted mb-4">Use criteria to enforce policies on which agents can authenticate. These are checked during sign-in and encoded into the receipt.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Criteria</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">allowedSignerTypes</td><td class="py-2 pr-4 text-muted font-mono text-xs">('eoa' | 'sca')[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">Restrict to EOA-only or allow smart contract accounts.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">mustBeActive</td><td class="py-2 pr-4 text-muted font-mono text-xs">boolean</td><td class="py-2 pr-4 text-muted font-mono text-xs">Require agent metadata.active === true.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">requiredServices</td><td class="py-2 pr-4 text-muted font-mono text-xs">string[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent must support these services (e.g., 'llm', 'web3').</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">requiredTrust</td><td class="py-2 pr-4 text-muted font-mono text-xs">string[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent must support these trust models (e.g., 'tee', 'crypto-economic').</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">minScore</td><td class="py-2 pr-4 text-muted font-mono text-xs">number</td><td class="py-2 pr-4 text-muted font-mono text-xs">Minimum reputation score (requires reputationRegistryAddress).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">minFeedbackCount</td><td class="py-2 pr-4 text-muted font-mono text-xs">number</td><td class="py-2 pr-4 text-muted font-mono text-xs">Minimum feedback count (requires reputationRegistryAddress).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">reputationRegistryAddress</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Reputation registry address for score/feedback checks.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">custom</td><td class="py-2 pr-4 text-muted font-mono text-xs">(agent) => Promise<boolean></td><td class="py-2 pr-4 text-muted font-mono text-xs">Custom validation function with full agent profile.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">The result includes <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">signerType</code> and optionally <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">agent</code> (full profile if criteria fetched metadata).</p><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">Nonce Endpoint Examples</h4><p class="text-xs text-dim mt-1">Issue a nonce for the agent to sign. Import <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createSIWANonce</code> from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa</code>.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Next.js Nonce Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
39<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// app/api/siwa/nonce/route.ts 40import { createSIWANonce } from "@buildersgarden/siwa"; 41import { corsJson, siwaOptions } from "@buildersgarden/siwa/next";<!-- --> 42...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Express Nonce Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// routes/siwa.ts 43import express from "express"; 44import { createSIWANonce } from "@buildersgarden/siwa";<!-- --> 45...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Hono Nonce Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// src/routes/siwa.ts 46import { Hono } from "hono"; 47import { cors } from "hono/cors";<!-- --> 48...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Fastify Nonce Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// src/routes/siwa.ts 49import { FastifyPluginAsync } from "fastify"; 50import { createSIWANonce } from "@buildersgarden/siwa";<!-- --> 51...</code></pre></div></div><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">Verify Endpoint Examples</h4><p class="text-xs text-dim mt-1">Verify the signed message and issue a receipt.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Next.js Verify Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
51<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// app/api/siwa/verify/route.ts 52import { verifySIWA } from "@buildersgarden/siwa"; 53import { createReceipt } from "@buildersgarden/siwa/receipt";<!-- --> 54...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Express Verify Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// routes/siwa.ts (add to same router as nonce) 55import { verifySIWA } from "@buildersgarden/siwa"; 56import { createReceipt } from "@buildersgarden/siwa/receipt";<!-- --> 57...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Hono Verify Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// src/routes/siwa.ts (add to same app as nonce) 58import { verifySIWA } from "@buildersgarden/siwa"; 59import { createReceipt } from "@buildersgarden/siwa/receipt";<!-- --> 60...</code></pre></div></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Fastify Verify Endpoint</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// src/routes/siwa.ts (add to same plugin as nonce) 61import { verifySIWA } from "@buildersgarden/siwa"; 62import { createReceipt } from "@buildersgarden/siwa/receipt";<!-- --> 63...</code></pre></div></div></div><div id="verify-erc8128" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">ERC-8128 Request Verification</h3><p class="text-sm leading-relaxed text-muted mb-4">Verify incoming ERC-8128 signed requests from authenticated agents.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">
63verifyAuthenticatedRequest(req, options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">AuthResult</td><td class="py-2 pr-4 text-muted font-mono text-xs">Verify incoming signed request.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/erc8128</code>. Options accept <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">allowedSignerTypes</code> for policy enforcement. The verified agent includes a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">signerType</code> field.</p></div><div id="verify-receipts" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Receipts</h3><p class="text-sm leading-relaxed text-muted mb-4">Stateless HMAC-signed tokens issued after successful SIWA verification. The agent includes the receipt in subsequent requests, and the server verifies it.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">createReceipt(payload, options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">{ receipt, expiresAt }</td><td class="py-2 pr-4 text-muted font-mono text-xs">Create an HMAC-signed receipt.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">verifyReceipt(receipt, secret)</td><td class="py-2 pr-4 text-muted font-mono text-xs">ReceiptPayload | null</td><td class="py-2 pr-4 text-muted font-mono text-xs">Verify and decode. Returns null if invalid.</td></tr></tbody></table></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Payload Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">address</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent wallet address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">agentId</td><td class="py-2 pr-4 text-muted font-mono text-xs">number</td><td class="py-2 pr-4 text-muted font-mono text-xs">ERC-8004 token ID.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">signerType</td><td class="py-2 pr-4 text-muted font-mono text-xs">SignerType?</td><td class="py-2 pr-4 text-muted font-mono text-xs">Optional: 'eoa' or 'sca'.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/receipt</code>.</p></div><div id="verify-wrappers" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Server Middleware</h3><p class="text-sm leading-relaxed text-muted mb-4">Drop-in middleware for popular frameworks. Each handles ERC-8128 verification, receipt checking, and CORS.</p><div class="rounded-lg border border-accent/30 bg-accent/5 px-4 py-3 mb-6"><p class="text-sm text-muted leading-relaxed"><span class="font-mono font-semibold text-accent">Note:</span> <!-- -->ERC-8004 criteria (reputation, services, trust models) are checked during SIWA sign-in via<!-- --> <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verifySIWA()</code>. The middleware below verifies ERC-8128 signatures on subsequent requests â it accepts<!-- --> <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">allowedSignerTypes</code> and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verifyOnchain</code> options for per-request policy.</p></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Option</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">receiptSecret</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">HMAC secret for receipt verification. Defaults to RECEIPT_SECRET env.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">allowedSignerTypes</td><td class="py-2 pr-4 text-muted font-mono text-xs">('eoa' | 'sca')[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">Restrict to EOA-only or SCA-only agents.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">
63verifyOnchain</td><td class="py-2 pr-4 text-muted font-mono text-xs">boolean</td><td class="py-2 pr-4 text-muted font-mono text-xs">Re-check ownerOf on every request (slower but more secure).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">rpcUrl</td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">RPC URL for onchain verification.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">publicClient</td><td class="py-2 pr-4 text-muted font-mono text-xs">PublicClient</td><td class="py-2 pr-4 text-muted font-mono text-xs">viem PublicClient for ERC-1271 smart account signatures.</td></tr></tbody></table></div><div id="verify-wrappers-next" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Next.js (App Router)</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/next</code> â exports: withSiwa, siwaOptions, corsJson</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Next.js Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// app/api/protected/route.ts 64import { withSiwa, siwaOptions } from "@buildersgarden/siwa/next"; 65<!-- --> 66...</code></pre></div></div><div id="verify-wrappers-express" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Express</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/express</code> â exports: siwaMiddleware, siwaJsonParser, siwaCors</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Express Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import express from "express"; 67import { siwaMiddleware, siwaJsonParser, siwaCors } from "@buildersgarden/siwa/express"; 68import { createPublicClient, http } from "viem";<!-- --> 69...</code></pre></div></div><div id="verify-wrappers-hono" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Hono</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/hono</code> â exports: siwaMiddleware, siwaCors</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Hono Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
69<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { Hono } from "hono"; 70import { siwaMiddleware, siwaCors } from "@buildersgarden/siwa/hono"; 71import { createPublicClient, http } from "viem";<!-- --> 72...</code></pre></div></div><div id="verify-wrappers-fastify" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Fastify</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/fastify</code> â exports: siwaPlugin, siwaAuth</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Fastify Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import Fastify from "fastify"; 73import { siwaPlugin, siwaAuth } from "@buildersgarden/siwa/fastify"; 74import { createPublicClient, http } from "viem";<!-- --> 75...</code></pre></div></div></div><div id="nonce-store" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Nonce Store</h3><p class="text-sm leading-relaxed text-muted mb-4">Pluggable server-side nonce tracking for replay protection. The SDK ships built-in adapters for Memory, Redis, Cloudflare KV, and any SQL database â no extra dependencies, you bring your own client.</p></div><div id="nonce-why" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Why Nonces Matter</h3><p class="text-sm leading-relaxed text-muted mb-4">A SIWA message is valid for its entire TTL window (default 5 minutes). Without server-side tracking, an attacker who intercepts a signed message can <strong class="text-foreground">replay</strong> it â submitting the same signature multiple times to authenticate as the agent.</p><p class="text-sm leading-relaxed text-muted mb-4">A nonce store solves this by recording every issued nonce and consuming it on first use. Once consumed, the nonce is deleted and any replay attempt is rejected.</p><p class="text-sm leading-relaxed text-muted mb-4">The SDK provides three nonce validation strategies:</p><ul class="space-y-2 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span><strong class="text-foreground">Callback</strong> â <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">(nonce) => boolean</code>: you manage nonce storage yourself</span></li><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span><strong class="text-foreground">Stateless token</strong> â <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">{ nonceToken, secret }</code>: HMAC-signed token, no server storage needed (but replayable within TTL)</span></li><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span><strong class="text-foreground">Nonce store</strong> â <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">{ nonceStore }</code>: server-side tracking with exactly-once consumption (recommended for production)</span></li></ul><p class="text-sm leading-relaxed text-muted mb-4">The <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">SIWANonceStore</code> interface:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">SIWANonceStore</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token doc-comment comment" style="color:rgb(99, 119, 119);font-style:italic">/** Store an issued nonce. Returns true on success, false if already exists. */</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">issue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ttlMs</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">
75Promise</span><span class="token operator" style="color:rgb(127, 219, 202)"><</span><span class="token builtin" style="color:rgb(130, 170, 255)">boolean</span><span class="token operator" style="color:rgb(127, 219, 202)">></span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token doc-comment comment" style="color:rgb(99, 119, 119);font-style:italic">/** Atomically check-and-delete a nonce. Returns true if it existed. */</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">consume</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">Promise</span><span class="token operator" style="color:rgb(127, 219, 202)"><</span><span class="token builtin" style="color:rgb(130, 170, 255)">boolean</span><span class="token operator" style="color:rgb(127, 219, 202)">></span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Wire the store into both <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createSIWANonce</code> (issue) and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verifySIWA</code> (consume):</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createSIWANonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> verifySIWA </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createMemorySIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/nonce-store"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 76</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createMemorySIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 77</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Nonce endpoint â issue</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createSIWANonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 78</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Verify endpoint â consume</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> verification </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">verifySIWA</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> message</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> domain</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="nonce-memory" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Memory (Default)</h3><p class="text-sm leading-relaxed text-muted mb-4">In-memory store using a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Map</code> with TTL-based expiry. Suitable for single-process servers. Nonces are lost on restart.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
78import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createMemorySIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/nonce-store"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 79</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createMemorySIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="nonce-redis" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Redis</h3><p class="text-sm leading-relaxed text-muted mb-4">Redis-backed store using <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">SET ... PX ttl NX</code> for atomic issue and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">DEL</code> for atomic consume. Works with any Redis client that implements <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">set()</code> and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">del()</code>.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createRedisSIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/nonce-store"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 80</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// ioredis (works out of the box)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> Redis </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"ioredis"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> redis </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Redis</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createRedisSIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">redis</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">For <strong class="text-foreground">node-redis v4</strong>, wrap with a small adapter since its <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">set()</code> signature differs:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
80import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createClient </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"redis"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createRedisSIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/nonce-store"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 81</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> client </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 82</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createRedisSIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">set</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(127, 219, 202)">...</span><span class="token plain">args</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">unknown</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> client</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">PX</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">3</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">NX</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">
82then</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">r</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"> r </span><span class="token operator" style="color:rgb(127, 219, 202)">??</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">del</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">unknown</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">del</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">key </span><span class="token keyword" style="color:rgb(127, 219, 202)">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="nonce-kv" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Cloudflare KV</h3><p class="text-sm leading-relaxed text-muted mb-4">Cloudflare Workers KV-backed store. Uses <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">put</code> with <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">expirationTtl</code> for auto-expiry. The consume path does a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">get</code> + <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">delete</code> â not fully atomic, but acceptable for random nonces.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createKVSIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/nonce-store"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 83</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// In a Cloudflare Worker</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">default</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">request</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> env</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> Env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createKVSIWANonceStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">
83env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_NONCES</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// use with createSIWANonce / verifySIWA</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Bind a KV namespace called <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">SIWA_NONCES</code> in your <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">wrangler.toml</code>:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">[[kv_namespaces]]</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">binding = "SIWA_NONCES"</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">id = "<your-kv-namespace-id>"</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="nonce-database" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Database</h3><p class="text-sm leading-relaxed text-muted mb-4">For databases, implement <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">SIWANonceStore</code> directly â it's just two methods. No factory needed.</p><p class="text-sm leading-relaxed text-muted mb-4"><strong class="text-foreground">Schema</strong> â create a table with a unique nonce column and an expiry timestamp:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">CREATE TABLE siwa_nonces (</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> nonce VARCHAR(64) PRIMARY KEY,</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> expires_at TIMESTAMPTZ NOT NULL</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">);</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">-- Optional: periodic cleanup of expired rows</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">-- DELETE FROM siwa_nonces WHERE expires_at < NOW();</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4"><strong class="text-foreground">Prisma</strong>:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
83import</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> SIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/nonce-store"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 84</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> SIWANonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">issue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ttlMs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> prisma</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">siwaNonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">create</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> data</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> expiresAt</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">+</span><span class="token plain"> ttlMs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">code </span><span class="token operator" style="color:rgb(127, 219, 202)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"P2002"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">
84false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// unique constraint</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">throw</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">consume</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> prisma</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">siwaNonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">delete</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> where</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonce </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">
84false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4"><strong class="text-foreground">Drizzle</strong>:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> SIWANonceStore </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/nonce-store"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> eq</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> and</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> gt </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"drizzle-orm"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> siwaNonces </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"./schema"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 85</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> nonceStore</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> SIWANonceStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">issue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ttlMs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> db</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">insert</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">siwaNonces</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> expiresAt</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">+</span><span class="token plain"> ttlMs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">code </span><span class="token operator" style="color:rgb(127, 219, 202)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"23505"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">
85false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// unique violation</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">throw</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">consume</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> db</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">delete</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">siwaNonces</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">where</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">and</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">eq</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">siwaNonces</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> nonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">gt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">siwaNonces</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">expiresAt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">rowCount </span><span class="token operator" style="color:rgb(127, 219, 202)">??</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">></span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="captcha-how" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Captcha (Reverse CAPTCHA)</h3><p class="text-sm leading-relaxed text-muted mb-4">SIWA includes a <strong class="text-foreground">reverse CAPTCHA</strong> â inspired by <a href="https://github.com/MoltCaptcha/MoltCaptcha" class="text-accent hover:underline" target="_blank" rel="noopener noreferrer">MoltCaptcha</a> â that proves an entity <em>is</em> an AI agent, not a human. Challenges exploit how LLMs generate text in a single autoregressive pass, satisfying multiple constraints simultaneously, while humans must iterate.</p><p class="text-sm leading-relaxed text-muted mb-4">The server generates a challenge with constraints the agent must satisfy in its response text â line count, sum of ASCII values of first characters, word count, character at a specific position, and total character count. Higher difficulty levels add more constraints with tighter time limits.</p><p class="text-sm leading-relaxed text-muted mb-4">Two integration points:</p><ul class="space-y-2 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span><strong class="text-foreground">Sign-in flow</strong> â server requires captcha before issuing a nonce</span></li><li class="flex gap-3"><span class="text-accent shrink-0">â¢</span><span><strong class="text-foreground">Per-request</strong> â middleware randomly challenges agents during authenticated API calls (server-defined policy/probability)</span></li></ul></div><div id="captcha-signin" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Sign-In Captcha</h3><p class="text-sm leading-relaxed text-muted mb-4">Add <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaPolicy</code> and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaOptions</code> to your nonce endpoint. The policy function receives the agent's identity and returns a difficulty level or <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">null</code> to skip.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
85import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createSIWANonce </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 86</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createSIWANonce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> agentId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> agentRegistry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> challengeResponse </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">captchaPolicy</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> address </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> known </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> db</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">agents</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">exists</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> known </span><span class="token operator" style="color:rgb(127, 219, 202)">?</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'medium'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// challenge unknown agents</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> captchaOptions</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">
86 secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 87</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// result.status is 'captcha_required' | 'nonce_issued' | SIWAResponse</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Agent-side: use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">solveCaptchaChallenge()</code> to detect and solve in one step.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> solveCaptchaChallenge </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/captcha"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 88</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> res </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"/api/siwa/nonce"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"POST"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> agentId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> agentRegistry </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> data </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 89</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> captcha </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">solveCaptchaChallenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">challenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// LLM generates text satisfying all constraints in a single pass</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Your LLM generates text satisfying all constraints in one pass.</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Use any provider (Anthropic, OpenAI, etc.) â just return a string.</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">generateText</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">challenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 90</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">captcha</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">solved</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Retry with challengeResponse</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">"/api/siwa/nonce"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"POST"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> body</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">...</span><span class="token plain">params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> challengeResponse</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> captcha</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">challengeResponse </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div>
90<div id="captcha-perrequest" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Per-Request Captcha</h3><p class="text-sm leading-relaxed text-muted mb-4">Add <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaPolicy</code> to middleware for random spot-checks on authenticated requests.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Next.js</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">POST</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">withSiwa</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">handler</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">captchaPolicy</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> request </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">request</span><span class="token operator" style="color:rgb(127, 219, 202)">?.</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">includes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(173, 219, 103)">'/transfer'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">&&</span><span class="token plain"> Math</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">random</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)"><</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0.05</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'hard'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">return</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> captchaOptions</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">
90 secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token operator" style="color:rgb(127, 219, 202)">!</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 91</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Express</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">siwaMiddleware</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">captchaPolicy</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"> Math</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">random</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)"><</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0.05</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">?</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'easy'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> captchaOptions</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Agent-side: use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">retryWithCaptcha()</code> to detect a 401 captcha challenge, solve it, re-sign with ERC-8128, and get a ready-to-send retry request.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
91import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> signAuthenticatedRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> retryWithCaptcha </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/erc8128"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 92</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> url </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"https://api.example.com/action"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> body </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> key</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"value"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 93</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Sign and send</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> signed </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">signAuthenticatedRequest</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"POST"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> body </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> receipt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> chainId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> response </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">signed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 94</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Detect + solve + re-sign if captcha required</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">retryWithCaptcha</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">Request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> method</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"POST"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> body </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// fresh request</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> receipt</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> signer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> chainId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">challenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">generateText</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">challenge</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// your LLM solver</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 95</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">retry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> retryResponse </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">request</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="captcha-difficulty" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Difficulty Levels & Configuration</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Level</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Time Limit</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Constraints</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">easy</td><td class="py-2 pr-4 text-muted font-mono text-xs">30s</td><td class="py-2 pr-4 text-muted font-mono text-xs">Line count + ASCII sum of first chars</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">medium</td><td class="py-2 pr-4 text-muted font-mono text-xs">20s</td><td class="py-2 pr-4 text-muted font-mono text-xs">+ word count</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">hard</td><td class="py-2 pr-4 text-muted font-mono text-xs">15s</td><td class="py-2 pr-4 text-muted font-mono text-xs">+ character at specific position</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">extreme</td><td class="py-2 pr-4 text-muted font-mono text-xs">10s</td><td class="py-2 pr-4 text-muted font-mono text-xs">+ total character count</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">All verification behavior is configurable via <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaOptions.verify</code>:</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Option</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Default</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">useServerTiming</td><td class="py-2 pr-4 text-muted font-mono text-xs">true</td><td class="py-2 pr-4 text-muted font-mono text-xs">Use server wall-clock time instead of trusting the agent's solvedAt.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">timingToleranceSeconds</td><td class="py-2 pr-4 text-muted font-mono text-xs">2</td><td class="py-2 pr-4 text-muted font-mono text-xs">Extra seconds added to time limit for network latency.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">asciiTolerance</td><td class="py-2 pr-4 text-muted font-mono text-xs">0</td><td class="py-2 pr-4 text-muted font-mono text-xs">Allow ±N tolerance on ASCII sum comparison.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">revealConstraints</td><td class="py-2 pr-4 text-muted font-mono text-xs">true</td><td class="py-2 pr-4 text-muted font-mono text-xs">Include actual vs target values in verification results.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">consumeChallenge</td><td class="py-2 pr-4 text-muted font-mono text-xs">â</td><td class="py-2 pr-4 text-muted font-mono text-xs">Callback for one-time-use tokens. Return false to reject replays.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Override difficulty settings per tier with <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">captchaOptions.difficulties</code>:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4
95 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">captchaOptions</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> secret</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SIWA_SECRET</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> verify</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> useServerTiming</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> timingToleranceSeconds</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> revealConstraints</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">consumeChallenge</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">token</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"> redis</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(173, 219, 103)">`</span><span class="token template-string string" style="color:rgb(173, 219, 103)">captcha:</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">token</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(173, 219, 103)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'1'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'NX'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'EX'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">60</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">
95then</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">r </span><span class="token operator" style="color:rgb(127, 219, 202)">=></span><span class="token plain"> r </span><span class="token operator" style="color:rgb(127, 219, 202)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">'OK'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> difficulties</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> easy</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> timeLimitSeconds</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">45</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> extreme</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> timeLimitSeconds</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">8</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/captcha</code>.</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Export</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Side</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">solveCaptchaChallenge(nonceResponse, solver)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Detect + solve captcha from nonce response.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">retryWithCaptcha(response, request, ...)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Detect captcha in 401, solve, re-sign, return retry request. (from erc8128 module)</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">packCaptchaResponse(token, text)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Package solution for submission.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">createCaptchaChallenge(difficulty, opts)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Server</td><td class="py-2 pr-4 text-muted font-mono text-xs">Generate challenge + HMAC-signed token.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">
95verifyCaptchaSolution(token, solution, secret, verifyOpts?)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Server</td><td class="py-2 pr-4 text-muted font-mono text-xs">Verify all constraints + timing. Async.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">unpackCaptchaResponse(packed)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Server</td><td class="py-2 pr-4 text-muted font-mono text-xs">Unpack agent response.</td></tr></tbody></table></div></div></section><section id="x402" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">x402 Payments</h2><div id="x402-overview" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Overview</h3><p class="text-sm leading-relaxed text-muted mb-4">The <a href="https://www.x402.org/" target="_blank" rel="noopener noreferrer" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">x402 protocol</a> adds pay-per-request monetization to any SIWA-protected endpoint. When a route requires payment, the middleware enforces a two-gate flow: <strong class="text-foreground">SIWA authentication first</strong>, then <strong class="text-foreground">payment verification</strong>. Both must pass before the handler runs.</p><ol class="space-y-3 mb-6 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">1.</span><span>Agent sends a request with <strong class="text-foreground">ERC-8128 SIWA headers</strong> (always required).</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">2.</span><span>Middleware verifies SIWA identity. If invalid, returns <strong class="text-foreground">401</strong>.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">3.</span><span>If no <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Signature</code> header is present, returns <strong class="text-foreground">402</strong> with a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Required</code> header containing accepted payment options.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">4.</span><span>Agent constructs a payment, encodes it as a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Signature</code> header, and retries.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">5.</span><span>Middleware sends the payment to a <strong class="text-foreground">facilitator</strong> for verification and on-chain settlement.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">6.</span><span>On success, the handler runs and the response includes a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Response</code> header with the transaction hash.</span></li></ol><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Header</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Direction</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Required</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">Server to Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Base64-encoded JSON with accepted payment options. Sent with 402 responses.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Signature</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent to Server</td><td class="py-2 pr-4 text-muted font-mono text-xs">Base64-encoded signed payment payload from the agent.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Response</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">Server to Agent</td><td class="py-2 pr-4 text-muted font-mono text-xs">Base64-encoded settlement result with transaction hash.</td></tr></tbody></table></div></div><div id="x402-server" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Server Setup</h3><p class="text-sm leading-relaxed text-muted mb-4">Three things are needed to enable x402 on a route: a <strong class="text-foreground">facilitator client</strong> (verifies and settles payments), a <strong class="text-foreground">resource description</strong>, and an <strong class="text-foreground">accepts array</strong>
95 listing payment options.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> createFacilitatorClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">X402Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/x402"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 96</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// 1. Create facilitator client</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> facilitator </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createFacilitatorClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> url</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"https://x402-facilitator.example.com"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 97</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// 2. Define x402 config</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> x402</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> X402Config </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> facilitator</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> resource</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> url</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"/api/premium"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> description</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"Premium data access"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> accepts</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> scheme</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"exact"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> network</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"eip155:84532"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Base Sepolia</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> amount</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"1000000"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// 1 USDC (6 decimals)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> asset</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"0x036CbD53842c5426634e7929541eC2318f3dCF7e"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> payTo</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"0xYourAddress"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> maxTimeoutSeconds</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">60</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Pass the <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">x402</code> config to any framework middleware. Routes without <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">x402</code> remain SIWA-only (free).</p></div><div id="x402-sessions" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Sessions (Pay-Once)</h3><p class="text-sm leading-relaxed text-muted mb-4">By default, every request requires a new payment. Add <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">session</code> to the x402 config to enable <strong class="text-foreground">pay-once mode</strong>: the agent pays on the first request and subsequent requests within the TTL window pass through without payment.</p><p class="text-sm leading-relaxed text-muted mb-4">Sessions are keyed by <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">(address, resource.url)</code> â different agents and different routes are isolated from each other.</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">
97import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> createFacilitatorClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> createMemoryX402SessionStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"@buildersgarden/siwa/x402"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 98</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> facilitator </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createFacilitatorClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> url</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">X402_FACILITATOR_URL</span><span class="token operator" style="color:rgb(127, 219, 202)">!</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 99</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// In-memory store (use Redis/DB in production)</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> sessionStore </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createMemoryX402SessionStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 100</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// Pass to any middleware</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">const</span><span class="token plain"> x402Config </span><span class="token operator" style="color:rgb(127, 219, 202)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> facilitator</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> resource</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> url</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"/api/premium"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> description</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(173, 219, 103)">"Premium access"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> accepts</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">/* ... */</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> session</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> store</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> sessionStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> ttl</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">3600_000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(99, 119, 119);font-style:italic">// 1 hour</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">On the first request, the agent pays and the middleware stores a session. On subsequent requests from the same agent to the same resource, the session is found and payment is skipped. After TTL expiry, payment is required again.</p><p class="text-sm leading-relaxed text-muted mb-4">For production, implement the <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">X402SessionStore</code> interface with a shared store:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token keyword" style="color:rgb(127, 219, 202)">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">X402SessionStore</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">
100get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> resource</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">Promise</span><span class="token operator" style="color:rgb(127, 219, 202)"><</span><span class="token plain">X402Session </span><span class="token operator" style="color:rgb(127, 219, 202)">|</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(127, 219, 202)">null</span><span class="token operator" style="color:rgb(127, 219, 202)">></span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> resource</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> session</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> X402Session</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ttlMs</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">Promise</span><span class="token operator" style="color:rgb(127, 219, 202)"><</span><span class="token keyword" style="color:rgb(127, 219, 202)">void</span><span class="token operator" style="color:rgb(127, 219, 202)">></span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 101</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token keyword" style="color:rgb(127, 219, 202)">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 139)">X402Session</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> paidAt</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> txHash</span><span class="token operator" style="color:rgb(127, 219, 202)">?</span><span class="token operator" style="color:rgb(127, 219, 202)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="x402-config" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Config Reference</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">facilitator</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">FacilitatorClient</td><td class="py-2 pr-4 text-muted font-mono text-xs">Client for payment verification and settlement.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">resource</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">ResourceInfo</td><td class="py-2 pr-4 text-muted font-mono text-xs">The resource being paid for: { url, description? }.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">accepts</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">PaymentRequirements[]</td><td class="py-2 pr-4 text-muted font-mono text-xs">
101Array of accepted payment options.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">session?</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">X402SessionConfig</td><td class="py-2 pr-4 text-muted font-mono text-xs">Optional pay-once session: { store, ttl }.</td></tr></tbody></table></div><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">PaymentRequirements</h4></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">scheme</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Payment scheme (e.g. <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">"exact"</code>).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">network</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Chain identifier (e.g. <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">"eip155:84532"</code>).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">amount</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Payment amount in smallest unit (e.g. wei, USDC base units).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">asset</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Token contract address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">payTo</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Recipient address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">maxTimeoutSeconds?</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">number</td><td class="py-2 pr-4 text-muted font-mono text-xs">Maximum time for settlement.</td></tr></tbody></table></div><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">X402Payment (verified payment on request)</h4></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">scheme</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Payment scheme.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">network</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Chain identifier.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">amount</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Amount paid.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">asset</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Token address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">payTo</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">Recipient address.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">txHash?</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">string</td><td class="py-2 pr-4 text-muted font-mono text-xs">On-chain transaction hash from settlement.</td></tr></tbody></table></div><div class="mt-6 mb-3"><h4 class="font-mono text-sm font-semibold text-foreground">FacilitatorClient</h4></div><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Method</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">verify(payload, requirements)</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">VerifyResponse</td><td class="py-2 pr-4 text-muted font-mono text-xs">Validate a payment signature.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs"><code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">settle(payload, requirements)</code></td><td class="py-2 pr-4 text-muted font-mono text-xs">SettleResponse</td><td class="py-2 pr-4 text-muted font-mono text-xs">Execute on-chain settlement. Returns txHash on success.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">createFacilitatorClient(<!-- -->{ url }<!-- -->)</code> to create a client that POSTs to <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/verify</code> and <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">/settle</code> endpoints on the facilitator. Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/x402</code>.</p></div><div id="x402-middleware" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Middleware</h3><p class="text-sm leading-relaxed text-muted mb-4">Each framework wrapper accepts an optional <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">x402</code> field. When set, both SIWA authentication <strong class="text-foreground">and</strong> a valid payment are required. The verified payment is available in the handler.</p><div id="x402-express" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Express</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/express</code>. Payment is available on <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">req.payment</code>.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Express x402 Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
101<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import express from "express"; 102import { siwaMiddleware, siwaJsonParser, siwaCors } from "@buildersgarden/siwa/express"; 103import { createFacilitatorClient } from "@buildersgarden/siwa/x402";<!-- --> 104...</code></pre></div></div><div id="x402-next" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Next.js</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/next</code>. Payment is the 3rd argument to the handler.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Next.js x402 Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>// app/api/premium/route.ts 105import { withSiwa, siwaOptions } from "@buildersgarden/siwa/next"; 106import { createFacilitatorClient } from "@buildersgarden/siwa/x402";<!-- --> 107...</code></pre></div></div><div id="x402-hono" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Hono</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/hono</code>. Payment is available via <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">c.get("payment")</code>.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Hono x402 Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { Hono } from "hono"; 108import { siwaMiddleware, siwaCors } from "@buildersgarden/siwa/hono"; 109import { createFacilitatorClient } from "@buildersgarden/siwa/x402";<!-- --> 110...</code></pre></div></div><div id="x402-fastify" class="scroll-mt-20 mt-8 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">Fastify</h4><p class="text-xs text-dim mb-3">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/fastify</code>. Payment is available on <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">req.payment</code>.</p></div><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Fastify x402 Example</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span>
110<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import Fastify from "fastify"; 111import { siwaPlugin, siwaAuth } from "@buildersgarden/siwa/fastify"; 112import { createFacilitatorClient } from "@buildersgarden/siwa/x402";<!-- --> 113...</code></pre></div></div></div><div id="x402-agent" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Agent-Side</h3><p class="text-sm leading-relaxed text-muted mb-4">When an agent receives a <strong class="text-foreground">402</strong> response, it should:</p><ol class="space-y-2 mb-4 text-sm leading-relaxed text-muted list-none"><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">1.</span><span>Read the <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Required</code> header and decode the payment options.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">2.</span><span>Construct a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">PaymentPayload</code> with the signed payment.</span></li><li class="flex gap-3"><span class="font-mono font-semibold text-accent shrink-0">3.</span><span>Encode it as a <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">Payment-Signature</code> header and retry the request.</span></li></ol><div class="rounded-lg border border-border bg-surface overflow-hidden mb-4"><button class="w-full flex items-center justify-between px-4 py-2.5 text-left hover:bg-background/50 transition-colors duration-200 cursor-pointer"><span class="font-mono text-sm font-medium text-foreground">Agent Payment Flow</span><div class="flex items-center gap-2"><span class="text-xs text-dim">expand</span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim transition-transform duration-200 "><polyline points="6 9 12 15 18 9"></polyline></svg></div></button><div class="border-t border-border px-4 py-3 bg-background/30"><pre class="font-mono text-xs text-dim leading-relaxed overflow-hidden"><code>import { 114 encodeX402Header, 115 decodeX402Header,<!-- --> 116...</code></pre></div></div></div></section><section id="identity" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Identity & Registry</h2><p class="text-sm leading-relaxed text-muted mb-4">Read and write agent identity state, and query onchain profiles.</p><div id="identity-file" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Identity File</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">ensureIdentityExists(path, template)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Initialize SIWA_IDENTITY.md if missing.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">readIdentity(path)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Parse SIWA_IDENTITY.md to typed object.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">writeIdentityField(key, value, path)</td><td class="py-2 pr-4 text-muted font-mono text-xs">Write a field to SIWA_IDENTITY.md.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">isRegistered({ identityPath, client? })</td><td class="py-2 pr-4 text-muted font-mono text-xs">Check registration status.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/identity</code>.</p></div><div id="identity-registry" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Onchain Registry</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Function</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Returns</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">registerAgent(options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">RegisterResult</td><td class="py-2 pr-4 text-muted font-mono text-xs">
116Register as ERC-8004 agent onchain.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">getAgent(agentId, options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">AgentProfile</td><td class="py-2 pr-4 text-muted font-mono text-xs">Read agent profile from registry.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">getReputation(agentId, options)</td><td class="py-2 pr-4 text-muted font-mono text-xs">ReputationSummary</td><td class="py-2 pr-4 text-muted font-mono text-xs">Read agent reputation.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">Import from <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">@buildersgarden/siwa/registry</code>.</p></div></section><section id="protocol" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Protocol Specification</h2><div id="protocol-message" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Message Format</h3><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">{domain} wants you to sign in with your Agent account:</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">{address}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 117</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">{statement}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 118</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">URI: {uri}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Version: 1</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Agent ID: {agentId}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Agent Registry: {agentRegistry}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Chain ID: {chainId}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Nonce: {nonce}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Issued At: {issuedAt}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">[Expiration Time: {expirationTime}]</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">[Not Before: {notBefore}]</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">[Request ID: {requestId}]</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div></div><div id="protocol-fields" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Field Definitions</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Field</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Required</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Description</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">domain</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">Origin domain requesting authentication.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">address</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent wallet address. Must be EIP-55 checksummed (mixed-case encoding).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">statement</td><td class="py-2 pr-4 text-muted font-mono text-xs">No</td><td class="py-2 pr-4 text-muted font-mono text-xs">Human-readable purpose string.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">uri</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">RFC 3986 URI of the resource.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">version</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">Must be "1".</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">agentId</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">ERC-721 tokenId in the Identity Registry (numeric).</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">agentRegistry</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">CAIP-10 reference: eip155:{chainId}:{registryAddress}. See Address Formatting.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">chainId</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">EIP-155 chain ID (numeric). Must match the chain in agentRegistry.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">nonce</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">Server-generated, >= 8 alphanumeric chars.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">issuedAt</td><td class="py-2 pr-4 text-muted font-mono text-xs">Yes</td><td class="py-2 pr-4 text-muted font-mono text-xs">RFC 3339 datetime.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">expirationTime</td><td class="py-2 pr-4 text-muted font-mono text-xs">No</td><td class="py-2 pr-4 text-muted font-mono text-xs">RFC 3339 datetime.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">notBefore</td><td class="py-2 pr-4 text-muted font-mono text-xs">No</td><td class="py-2 pr-4 text-muted font-mono text-xs">RFC 3339 datetime.</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">requestId</td><td class="py-2 pr-4 text-muted font-mono text-xs">No</td><td class="py-2 pr-4 text-muted font-mono text-xs">Opaque request identifier.</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">See <a href="#contracts-format" class="text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200">Address Formatting Standards</a> for details on CAIP-10, EIP-55, and EIP-155.</p></div><div id="protocol-vs-siwe" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">SIWA vs SIWE</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Aspect</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">SIWE (EIP-4361)</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">SIWA</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Purpose</td><td class="py-2 pr-4 text-muted font-mono text-xs">Human wallet auth</td><td class="py-2 pr-4 text-muted font-mono text-xs">Agent identity auth</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Identity proof</td><td class="py-2 pr-4 text-muted font-mono text-xs">Owns an Ethereum address</td><td class="py-2 pr-4 text-muted font-mono text-xs">Owns an ERC-8004 agent NFT</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Onchain check</td><td class="py-2 pr-4 text-muted font-mono text-xs">None required</td><td class="py-2 pr-4 text-muted font-mono text-xs">ownerOf(agentId) REQUIRED</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Extra fields</td><td class="py-2 pr-4 text-muted font-mono text-xs">None</td><td class="py-2 pr-4 text-muted font-mono text-xs">agentId, agentRegistry</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Signing</td><td class="py-2 pr-4 text-muted font-mono text-xs">EIP-191</td><td class="py-2 pr-4 text-muted font-mono text-xs">EIP-191 (same)</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Message prefix</td><td class="py-2 pr-4 text-muted font-mono text-xs">...your Ethereum account</td><td class="py-2 pr-4 text-muted font-mono text-xs">...your Agent account</td></tr></tbody></table></div></div></section><section id="contracts" class="scroll-mt-20 pb-16"><h2 class="font-mono text-xl font-semibold text-foreground mb-6">Contract Addresses</h2><div id="contracts-mainnet" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Mainnet</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain ID</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Identity Registry</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Reputation Registry</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum</td><td class="py-2 pr-4 text-muted font-mono text-xs">1</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A169FB4a3325136EB29fA0ceB6D2e539a432</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004BAa17C55a88189AE136b182e5fdA19dE9b63</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base</td><td class="py-2 pr-4 text-muted font-mono text-xs">8453</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A169FB4a3325136EB29fA0ceB6D2e539a432</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004BAa17C55a88189AE136b182e5fdA19dE9b63</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr></tbody></table></div></div><div id="contracts-testnet" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Testnets</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain ID</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Identity Registry</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">11155111</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A818BFB912233c491871b3d84c89A494BD9e</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A818BFB912233c491871b3d84c89A494BD9e"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">84532</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A818BFB912233c491871b3d84c89A494BD9e</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A818BFB912233c491871b3d84c89A494BD9e"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Linea Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">59141</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A818BFB912233c491871b3d84c89A494BD9e</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A818BFB912233c491871b3d84c89A494BD9e"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-mu
118ted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Polygon Amoy</td><td class="py-2 pr-4 text-muted font-mono text-xs">80002</td><td class="py-2 pr-4"><span class="inline-flex items-center gap-1.5 group"><code class="font-mono text-xs text-muted">0x8004A818BFB912233c491871b3d84c89A494BD9e</code><button class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer" aria-label="Copy 0x8004A818BFB912233c491871b3d84c89A494BD9e"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-dim hover:text-muted"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg></button></span></td></tr></tbody></table></div></div><div id="contracts-format" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Address Formatting Standards</h3><p class="text-sm leading-relaxed text-muted mb-4">SIWA uses standardized address formats from the blockchain ecosystem:</p><div class="mt-4 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">CAIP-10: Agent Registry Reference</h4><p class="text-xs text-dim mt-1 mb-3"><a href="https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md" target="_blank" rel="noopener noreferrer" class="text-accent hover:underline">CAIP-10</a> (Chain Agnostic Improvement Proposal) defines a standard way to reference blockchain accounts across different networks.</p></div><p class="text-sm leading-relaxed text-muted mb-4">The <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">agentRegistry</code> field uses CAIP-10 format to uniquely identify the ERC-8004 Identity Registry contract on a specific chain:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">{namespace}:{chainId}:{contractAddress}</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 119</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Format breakdown:</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> namespace = "eip155" (EVM-compatible chains per EIP-155)</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> chainId = numeric chain identifier (e.g., 8453 for Base)</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> contractAddress = EIP-55 checksummed contract address</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain" style="display:inline-block"> 120</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Examples:</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (Base mainnet)</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e (Base Sepolia)</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain"> eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (Ethereum mainnet)</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><div class="mt-6 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">EIP-55: Checksummed Addresses</h4><p class="text-xs text-dim mt-1 mb-3"><a href="https://eips.ethereum.org/EIPS/eip-55" target="_blank" rel="noopener noreferrer" class="text-accent hover:underline">EIP-55</a> defines mixed-case checksum encoding for Ethereum addresses.</p></div><p class="text-sm leading-relaxed text-muted mb-4">All wallet addresses (<code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">address</code> field) must be EIP-55 checksummed. This provides error detection for typos:</p><div class="relative group"><pre class="overflow-x-auto rounded-lg border border-border bg-surface p-4 pr-12 font-mono text-sm leading-relaxed" style="color:#d6deeb;background-color:transparent"><code><div class="token-line" style="color:#d6deeb"><span class="token plain">Correct (checksummed): 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0</span></div><div class="token-line" style="color:#d6deeb"><span class="token plain">Incorrect (lowercase): 0x742d35cc6634c0532925a3b844bc9e7595f0beb0</span></div></code></pre><button class="absolute top-3 right-3 p-1.5 rounded text-dim hover:text-foreground transition-all duration-200 cursor-pointer" aria-label="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button></div><p class="text-sm leading-relaxed text-muted mb-4">Most libraries (viem, ethers.js) automatically return checksummed addresses. You can use <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">getAddress()</code> from viem to ensure proper formatting.</p><div class="mt-6 mb-2"><h4 class="font-mono text-sm font-semibold text-foreground">EIP-155: Chain IDs</h4><p class="text-xs text-dim mt-1 mb-3"><a href="https://eips.ethereum.org/EIPS/eip-155" target="_blank" rel="noopener noreferrer" class="text-accent hover:underline">EIP-155</a> introduced chain IDs to prevent replay attacks across different networks.</p></div><p class="text-sm leading-relaxed text-muted mb-4">The <code class="rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent">chainId</code> field identifies which blockchain network the agent is registered on. Common chain IDs:</p><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Network</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain ID</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Type</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum</td><td class="py-2 pr-4 text-muted font-mono text-xs">1</td><td class="py-2 pr-4 text-muted font-mono text-xs">Mainnet</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base</td><td class="py-2 pr-4 text-muted font-mono text-xs">8453</td><td class="py-2 pr-4 text-muted font-mono text-xs">Mainnet</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">84532</td><td class="py-2 pr-4 text-muted font-mono text-xs">Testnet</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">11155111</td><td class="py-2 pr-4 text-muted font-mono text-xs">Testnet</td></tr></tbody></table></div></div><div id="contracts-rpc" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Public RPC Endpoints</h3><div class="overflow-x-auto mb-4"><table class="w-full text-sm"><thead><tr class="border-b border-border"><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">Chain</th><th class="py-2 pr-4 text-left font-mono text-xs font-medium text-dim">RPC URL</th></tr></thead><tbody><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://mainnet.base.org</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Ethereum Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://rpc.sepolia.org</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Base Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://sepolia.base.org</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Linea Sepolia</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://rpc.sepolia.linea.build</td></tr><tr class="border-b border-border/50"><td class="py-2 pr-4 text-muted font-mono text-xs">Polygon Amoy</td><td class="py-2 pr-4 text-muted font-mono text-xs">https://rpc-amoy.polygon.technology</td></tr></tbody></table></div><p class="text-sm leading-relaxed text-muted mb-4">For production, use a provider like Alchemy or Infura with your own API key.</p></div><div id="contracts-explorer" class="scroll-mt-20 mt-8"><h3 class="font-mono text-base font-semibold text-foreground mb-4">Explorer</h3><p class="text-sm leading-relaxed text-muted mb-4">View registered agents at<!-- --> <a href="https://www.8004scan.io/" target="_blank" rel="noopener noreferrer" class="text-accent hover:text-blue-400 transition-colors duration-200 underline underline-offset-4 cursor-pointer">8004scan.io</a></p></div></section><div class="mt-4 grid gap-4 sm:grid-cols-2"><a href="/docs/endpoints" class="rounded-lg border border-border bg-surface p-5 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-sm font-semibold text-foreground mb-1">API Endpoints</h4><p class="text-xs text-muted">Live HTTP endpoints to try the full SIWA auth flow.</p></a><a href="/docs/deploy" class="rounded-lg border border-border bg-surface p-5 hover:border-accent/40 transition-colors duration-200 cursor-pointer block"><h4 class="font-mono text-sm font-semibold text-foreground mb-1">Deploy Keyring Proxy</h4><p class="text-xs text-muted">Self-hosted key management with optional 2FA for AI agents.</p></a></div></article></div><!--$--><!--/$--></main><footer class="border-t border-border py-8 text-sm text-dim"><div class="mx-auto max-w-5xl px-6 flex flex-col items-center gap-3"><div>Built by<!-- --> <a href="https://builders.garden" target="_blank" rel="noopener noreferrer" class="text-foreground hover:text-accent transition-colors duration-200 cursor-pointer">Builders Garden</a> <!-- -->&<!-- --> <a href="https://ai.ethereum.foundation/" target="_blank" rel="noopener noreferrer" class="text-foreground hover:text-accent transition-colors duration-200 cursor-pointer">dAI team</a></div><div>SIWA<!-- --> <span class="text-border mx-2">/</span> <a href="https://8004.org" target="_blank" rel="noopener noreferrer" class="hover:text-muted transition-colors duration-200 cursor-pointer">ERC-8004</a> <span class="text-border mx-2">/</span> <a href="https://erc8128.org/" target="_blank" rel="noopener noreferrer" class="hover:text-muted transition-colors duration-200 cursor-pointer">ERC-8128</a> <span class="text-border mx-2">/</span> <a href="https://github.com/builders-garden/siwa/blob/main/LICENSE" target="_blank" rel="noopener noreferrer" class="hover:text-muted transition-colors duration-200 cursor-pointer">MIT License</a></div></div></footer>
120<script src="/_next/static/chunks/7f7d21b762b07143.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7" id="_R_" async=""></script>
120<script>(self.__next_f=self.__next_f||[]).push([0])</script>
120<script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[26431,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"Navbar\"]\n3:I[3097,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"default\"]\n4:I[99299,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"default\"]\n5:I[24023,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"DocsSidebar\"]\n16:I[16153,[],\"default\"]\n:HL[\"/_next/static/chunks/43ec3b8db83f7d7e.css?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script>
120<script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"J85DJ4d2-pu0tm2EaWtIp\",\"c\":[\"\",\"docs\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"docs\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/43ec3b8db83f7d7e.css?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased font-sans\",\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"main\",null,{\"className\":\"pt-14\",\"children\":[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}],[\"$\",\"footer\",null,{\"className\":\"border-t border-border py-8 text-sm text-dim\",\"children\":[\"$\",\"div\",null,{\"className\":\"mx-auto max-w-5xl px-6 flex flex-col items-center gap-3\",\"children\":[[\"$\",\"div\",null,{\"children\":[\"Built by\",\" \",[\"$\",\"a\",null,{\"href\":\"https://builders.garden\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-foreground hover:text-accent transition-colors duration-200 cursor-pointer\",\"children\":\"Builders Garden\"}],\" \",\"\u0026\",\" \",[\"$\",\"a\",null,{\"href\":\"https://ai.ethereum.foundation/\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-foreground hover:text-accent transition-colors duration-200 cursor-pointer\",\"children\":\"dAI team\"}]]}],[\"$\",\"div\",null,{\"children\":[\"SIWA\",\" \",[\"$\",\"span\",null,{\"className\":\"text-border mx-2\",\"children\":\"/\"}],\" \",[\"$\",\"a\",null,{\"href\":\"https://8004.org\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"hover:text-muted transition-colors duration-200 cursor-pointer\",\"children\":\"ERC-8004\"}],\" \",[\"$\",\"span\",null,{\"className\":\"text-border mx-2\",\"children\":\"/\"}],\" \",[\"$\",\"a\",null,{\"href\":\"https://erc8128.org/\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"hover:text-muted transition-colors duration-200 cursor-pointer\",\"children\":\"ERC-8128\"}],\" \",[\"$\",\"span\",null,{\"className\":\"text-border mx-2\",\"children\":\"/\"}],\" \",[\"$\",\"a\",null,{\"href\":\"https://github.com/builders-garden/siwa/blob/main/LICENSE\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"hover:text-muted transition-colors duration-200 cursor-pointer\",\"children\":\"MIT License\"}]]}]]}]}]]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"div\",null,{\"className\":\"mx-auto flex max-w-6xl px-6 py-12\",\"children\":[[\"$\",\"$L5\",null,{}],[\"$\",\"article\",null,{\"className\":\"min-w-0 flex-1 pl-0 md:pl-12\",\"children\":[[\"$\",\"div\",null,{\"className\":\"mb-6 rounded-lg bg-yellow-500/10 border border-yellow-500/30 px-5 py-3\",\"children\":[\"$\",\"p\",null,{\"className\":\"text-sm font-mono text-yellow-400\",\"children\":[\"This project is a work in progress. Use at your own risk â we welcome\",\" \",[\"$\",\"a\",null,{\"href\":\"https://github.com/builders-garden/siwa\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"underline underline-offset-2 hover:text-yellow-300 transition-colors duration-200\",\"children\":\"feedback and contributions\"}],\".\"]}]}],\"$L6\",\"$L7\",\"$L8\",\"$L9\",\"$La\",\"$Lb\",\"$Lc\",\"$Ld\",\"$Le\",\"$Lf\",\"$L10\",\"$L11\"]}]]}],[\"$L12\",\"$L13\"],\"$L14\"]}],{}
120,null,false,false]},null,false,false]},null,false,false],\"$L15\",false]],\"m\":\"$undefined\",\"G\":[\"$16\",[]],\"S\":true}\n"])</script>
120<script>self.__next_f.push([1,"17:I[70832,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"GettingStartedTabs\"]\n18:I[80661,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"ImageModal\"]\n19:I[98067,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"CodeBlock\"]\n1a:I[98067,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"CollapsibleCodeBlock\"]\n56:I[33875,[\"/_next/static/chunks/da6c1156e80d635a.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"CopyableAddress\"]\n5a:I[36345,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"OutletBoundary\"]\n5b:\"$Sreact.suspense\"\n5d:I[36345,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"ViewportBoundary\"]\n5f:I[36345,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"MetadataBoundary\"]\n6:[\"$\",\"h1\",null,{\"className\":\"font-mono text-2xl font-bold text-foreground mb-2\",\"children\":\"SIWA Documentation\"}]\n7:[\"$\",\"p\",null,{\"className\":\"text-sm text-dim mb-8\",\"children\":\"Sign In With Agent â v1.0\"}]\n8:[\"$\",\"div\",null,{\"className\":\"mb-12 rounded-lg border border-accent/30 bg-accent/5 px-5 py-4\",\"children\":[[\"$\",\"p\",null,{\"className\":\"text-sm text-muted leading-relaxed\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent\",\"children\":\"What is SIWA?\"}],\" \",\"SIWA (Sign In With Agent) helps AI agents authenticate with services using their\",\" \",[\"$\",\"a\",null,{\"href\":\"https://8004.org\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"ERC-8004\"}],\" \",\"onchain identity. Like SIWE (Sign In With Ethereum) for humans, but for agents with verifiable registration.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm text-muted leading-relaxed mt-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent\",\"children\":\"For AI agents:\"}],\" \",\"Read\",\" \",[\"$\",\"a\",null,{\"href\":\"https://siwa.id/skill.md\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200 cursor-pointer\",\"children\":\"/skill.md\"}],\" \",\"for structured instructions.\"]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"9:[\"$\",\"section\",null,{\"id\":\"getting-started\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Getting Started\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"SIWA provides two core capabilities:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Agent-side:\"}],\" Sign SIWA messages to prove ownership of an ERC-8004 identity\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Server-side:\"}],\" Verify signatures and check onchain registration with multiple modular criteria\"]}]]}]]}],[\"$\",\"$L17\",null,{}],[\"$\",\"div\",null,{\"className\":\"mt-8 mb-4 grid gap-3 sm:grid-cols-3\",\"children\":[[\"$\",\"a\",null,{\"href\":\"#wallets\",\"className\":\"rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-xs font-semibold text-foreground mb-1\",\"children\":\"Wallet Options\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim\",\"children\":\"Use any wallet: Bankr, Circle, Openfort, Privy, private key, or keyring proxy.\"}]]}],[\"$\",\"a\",null,{\"href\":\"#api\",\"className\":\"rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-xs font-semibold text-foreground mb-1\",\"children\":\"API Reference\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim\",\"children\":\"SDK functions, modules, and types.\"}]]}],[\"$\",\"a\",null,{\"href\":\"#protocol\",\"className\":\"rounded-lg border border-border bg-surface px-4 py-3 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-xs font-semibold text-foreground mb-1\",\"children\":\"Protocol Spec\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim\",\"children\":\"Message format and authentication flow.\"}]]}]]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"a:[\"$\",\"section\",null,{\"id\":\"architecture\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"How It Works\"}],[\"$\",\"div\",null,{\"id\":\"auth-flow\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Authentication Flow\"}],[[\"$\",\"ol\",null,{\"className\":\"space-y-3 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[\"The agent requests a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"nonce\"}],\" from the service, sending its address and agent ID.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":\"The service returns the nonce along with timestamps.\"}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"3.\"}],[\"$\",\"span\",null,{\"children\":[\"The agent builds a SIWA message and \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"signs it\"}],\" with its wallet.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"4.\"}],[\"$\",\"span\",null,{\"children\":\"The agent sends the message and signature to the service.\"}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"5.\"}],[\"$\",\"span\",null,{\"children\":[\"The service \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"verifies\"}],\" the signature and calls the blockchain to confirm the agent owns that identity NFT.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"6.\"}],[\"$\",\"span\",null,{\"children\":[\"If verified, the service returns a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"receipt\"}],\". The agent uses this for subsequent authenticated requests.\"]}]]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"The SDK provides two main functions:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Agent-side:\"}],\" \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"signSIWAMessage(fields, signer)\"}],\" â builds and signs the message\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Server-side:\"}],\" \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verifySIWA(message, signature, domain, nonceValid, client, criteria?)\"}],\" â validates signature and checks onchain ownership\"]}]]}]]}],[\"$\",\"$L18\",null,{\"src\":\"/siwa-flow.png\",\"alt\":\"SIWA authentication flow: Agent requests nonce, signs SIWA message, Service verifies signature and checks onchain ownership, returns HMAC-signed verification receipt, then subsequent API requests use ERC-8128 HTTP signatures\",\"className\":\"w-full rounded-lg border border-border\",\"width\":800,\"height\"
120:730}]]]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"b:[\"$\",\"section\",null,{\"id\":\"signing\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Signing (Agent-Side)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Everything an agent needs to authenticate: choose a signer, sign SIWA messages for initial sign-in, then sign subsequent API requests with ERC-8128. \",[\"$\",\"br\",null,{}],\" SIWA supports both \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"EOA\"}],\" (Externally Owned Account) and \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"SCA\"}],\" (Smart Contract Account) signers â agents backed by smart wallets like Safe, Base Accounts, or ERC-6551 Token Bound Accounts work alongside traditional EOA-based agents.\"]}],[\"$\",\"div\",null,{\"id\":\"wallet-bankr\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Bankr\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Bankr's Agent API provides smart contract wallets (ERC-4337) for AI agents with built-in signing capabilities. No additional SDK is needed â the signer communicates directly with the Bankr API over HTTP. Signatures are verified via ERC-1271 automatically.\"}],[\"$\",\"$L19\",null,{\"language\":\"bash\",\"children\":\"# No extra package needed â only @buildersgarden/siwa\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Create a signer from your Bankr API key:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Bankr Signer Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createBankrSiwaSigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\n// Create signer - wallet address is fetched automatically from Bankr\\nconst signer = await createBankrSiwaSigner({\\n apiKey: process.env.BANKR_API_KEY!,\\n});\\n\\n// Sign SIWA message\\nconst { message, signature, address } = await signSIWAMessage({\\n domain: \\\"api.example.com\\\",\\n uri: \\\"https://api.example.com/siwa\\\",\\n agentId: 42,\\n agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n chainId: 84532,\\n nonce,\\n issuedAt: new Date().toISOString(),\\n}, signer);\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Already using Bankr's \",[\"$\",\"a\",null,{\"href\":\"https://github.com/BankrBot/openclaw-skills/tree/main/bankr\",\"className\":\"text-accent hover:underline\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"children\":\"OpenClaw trading skill\"}],\" for swaps and DeFi? This signer adds SIWA authentication on top â same API key, same wallet.\"]}]]]}],[\"$\",\"div\",null,{\"id\":\"wallet-circle\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Circle\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Circle's developer-controlled wallets provide secure key management for AI agents. Install the Circle SDK alongside SIWA:\"}],[\"$\",\"$L19\",null,{\"language\":\"bash\",\"children\":\"npm install @circle-fin/developer-controlled-wallets\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Create a signer from your Circle wallet credentials:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Circle Signer Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createCircleSiwaSigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\n// Create signer - wallet address is fetched automatically from Circle\\nconst signer = await createCircleSiwaSigner({\\n apiKey: process.env.CIRCLE_API_KEY!,\\n entitySecret: process.env.CIRCLE_ENTITY_SECRET!,\\n walletId: process.env.CIRCLE_WALLET_ID!,\\n});
120\\n\\n// Sign SIWA message\\nconst { message, signature, address } = await signSIWAMessage({\\n domain: \\\"api.example.com\\\",\\n uri: \\\"https://api.example.com/siwa\\\",\\n agentId: 42,\\n agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n chainId: 84532,\\n nonce,\\n issuedAt: new Date().toISOString(),\\n}, signer);\"}],\"$L1b\",\"$L1c\"]]}],\"$L1d\",\"$L1e\",\"$L1f\",\"$L20\",\"$L21\",\"$L22\",\"$L23\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"c:[\"$\",\"section\",null,{\"id\":\"verification\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Verification (Server-Side)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Everything a service needs to verify agents: validate SIWA sign-in, verify ERC-8128 signed requests, issue receipts, and plug into Express or Next.js.\"}],[\"$\",\"div\",null,{\"id\":\"verify-siwa\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"SIWA Verification\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Verify a signed SIWA message, check onchain ownership, and optionally validate ERC-8004 agent profile criteria. Implement two endpoints:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-4 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/siwa/nonce\"}],\" â Issue a nonce for the agent to sign\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/siwa/verify\"}],\" â Verify the signed message and issue a receipt\"]}]]}]]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifySIWA(msg, sig, domain, nonceValid, client, criteria?)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SIWAVerificationResult\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Verify signature + onchain ownership + criteria.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"parseSIWAMessage(message)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SIWAMessageFields\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Parse SIWA message string to fields.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa\"}],\". Parameters:\"]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Parameter\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Parameter\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"message\"}],\"$L24\",\"$L25\"]}],\"$L26\",\"$L27\",\"$L28\",\"$L29\",\"$L2a\"]}]]}]}],\"$L2b\",\"$L2c\",\"$L2d\",\"$L2e\",\"$L2f\",\"$L30\",\"$L31\",\"$L32\",\"$L33\",\"$L34\",\"$L35\",\"$L36\",\"$L37\",\"$L38\"]]}],\"$L39\",\"$L3a\",\"$L3b\",\"$L3c\",\"$L3d\",\"$L3e\",\"$L3f\",\"$L40\",\"$L41\",\"$L42\",\"$L43\",\"$L44\",\"$L45\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"d:[\"$\",\"section\",null,{\"id\":\"x402\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"x402 Payments\"}],[[\"$\",\"div\",null,{\"id\":\"x402-overview\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Overview\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The \",[\"$\",\"a\",null,{\"href\":\"https://www.x402.org/\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"x402 protocol\"}],\" adds pay-per-request monetization to any SIWA-protected endpoint. When a route requires payment, the middleware enforces a two-gate flow: \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"SIWA authentication first\"}],\", then \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"payment verification\"}],\". Both must pass before the handler runs.\"]}],[\"$\",\"ol\",null,{\"className\":\"space-y-3 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[\"Agent sends a request with \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"ERC-8128 SIWA headers\"}],\" (always required).\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":[\"Middleware verifies SIWA identity. If invalid, returns \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"401\"}],\".\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"3.\"}],[\"$\",\"span\",null,{\"children\":[\"If no \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Signature\"}],\" header is present, returns \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"402\"}],\" with a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Required\"}],\" header containing accepted payment options.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"4.\"}],[\"$\",\"span\",null,{\"children\":[\"Agent constructs a payment, encodes it as a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Signature\"}],\" header, and retries.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"5.\"}],[\"$\",\"span\",null,{\"children\":[\"Middleware sends the payment to a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"facilitator\"}],\" for verification and on-chain settlement.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"6.\"}],[\"$\",\"span\",null,{\"children\":[\"On success, the handler runs and the response includes a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Response\"}],\" header with the transaction hash.\"]}]]}]]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Header\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Header\"}],[\"$\",\"th\",\"Direction\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Direction\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],\"$L46\"]}]}]]]}],\"$L47\",\"$L48\",\"$L49\",\"$L4a\",\"$L4b\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"e:[\"$\",\"section\",null,{\"id\":\"identity\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Identity \u0026 Registry\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Read and write agent identity state, and query onchain profiles.\"}],[\"$\",\"div\",null,{\"id\":\"identity-file\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Identity File\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ensureIdentityExists(path, template)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Initialize SIWA_IDENTITY.md if missing.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"readIdentity(path)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Parse SIWA_IDENTITY.md to typed object.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"writeIdentityField(key, value, path)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Write a field to SIWA_IDENTITY.md.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"isRegistered({ identityPath, client? })\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Check registration status.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/identity\"}],\".\"]}]]]}],[\"$\",\"div\",null,{\"id\":\"identity-registry\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Onchain Registry\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"registerAgent(options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RegisterResult\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Register as ERC-8004 agent onchain.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"getAgent(agentId, options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"AgentProfile\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Read agent profile from registry.\"}]]}],\"$L4c\"]}]]}]}],\"$L4d\"]]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"f:[\"$\",\"section\",null,{\"id\":\"protocol\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Protocol Specification\"}],[[\"$\",\"div\",null,{\"id\":\"protocol-message\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Message Format\"}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"{domain} wants you to sign in with your Agent account:\\n{address}\\n\\n{statement}\\n\\nURI: {uri}\\nVersion: 1\\nAgent ID: {agentId}\\nAgent Registry: {agentRegistry}\\nChain ID: {chainId}\\nNonce: {nonce}\\nIssued At: {issuedAt}\\n[Expiration Time: {expirationTime}]\\n[Not Before: {notBefore}]\\n[Request ID: {requestId}]\"}]]}],[\"$\",\"div\",null,{\"id\":\"protocol-fields\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Field Definitions\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Field\"}],[\"$\",\"th\",\"Required\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Required\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"domain\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Origin domain requesting authentication.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"address\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent wallet address. Must be EIP-55 checksummed (mixed-case encoding).\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"statement\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"No\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Human-readable purpose string.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"uri\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RFC 3986 URI of the resource.\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"version\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Must be \\\"1\\\".\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"agentId\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ERC-721 tokenId in the Identity Registry (numeric).\"}]]}],[\"$\",\"tr\",\"6\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"agentRegistry\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"CAIP-10 reference: eip155:{chainId}:{registryAddress}. See Address Formatting.\"}]]}],\"$L4e\",\"$L4f\",\"$L50\",\"$L51\",\"$L52\",\"$L53\"]}]]}]}],\"$L54\"]]}],\"$L55\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"10:[\"$\",\"section\",null,{\"id\":\"contracts\",\"className\":\"scroll-mt-20 pb-16\",\"children\":[[\"$\",\"h2\",null,{\"className\":\"font-mono text-xl font-semibold text-foreground mb-6\",\"children\":\"Contract Addresses\"}],[[\"$\",\"div\",null,{\"id\":\"contracts-mainnet\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Mainnet\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain ID\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Identity Registry\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Reputation Registry\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"1\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A169FB4a3325136EB29fA0ceB6D2e539a432\"}]}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004BAa17C55a88189AE136b182e5fdA19dE9b63\"}]}]]}],[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"8453\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A169FB4a3325136EB29fA0ceB6D2e539a432\"}]}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004BAa17C55a88189AE136b182e5fdA19dE9b63\"}]}]]}]]}]]}]}]]}],[\"$\",\"div\",null,{\"id\":\"contracts-testnet\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Testnets\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain ID\"}],[\"$\",\"th\",null,{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Identity Registry\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum Sepolia\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"11155111\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A818BFB912233c491871b3d84c89A494BD9e\"}]}]]}],[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base Sepolia\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"84532\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A818BFB912233c491871b3d84c89A494BD9e\"}]}]]}],[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Linea Sepolia\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"59141\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A818BFB912233c491871b3d84c89A494BD9e\"}]}]]}],[\"$\",\"tr\",null,{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Polygon Amoy\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"80002\"}],[\"$\",\"td\",null,{\"className\":\"py-2 pr-4\",\"children\":[\"$\",\"$L56\",null,{\"address\":\"0x8004A818BFB912233c491871b3d84c89A494BD9e\"}]}]]}]]}]]}]}]]}],\"$L57\",\"$L58\",\"$L59\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"11:[\"$\",\"div\",null,{\"className\":\"mt-4 grid gap-4 sm:grid-cols-2\",\"children\":[[\"$\",\"a\",null,{\"href\":\"/docs/endpoints\",\"className\":\"rounded-lg border border-border bg-surface p-5 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground mb-1\",\"children\":\"API Endpoints\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-muted\",\"children\":\"Live HTTP endpoints to try the full SIWA auth flow.\"}]]}],[\"$\",\"a\",null,{\"href\":\"/docs/deploy\",\"className\":\"rounded-lg border border-border bg-surface p-5 hover:border-accent/40 transition-colors duration-200 cursor-pointer block\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground mb-1\",\"children\":\"Deploy Keyring Proxy\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-muted\",\"children\":\"Self-hosted key management with optional 2FA for AI agents.\"}]]}]]}]\n12:[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/b9e18a9181222732.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"async\":true,\"nonce\":\"$undefined\"}]\n13:[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/1d3b3a30a1d781ce.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"async\":true,\"nonce\":\"$undefined\"}]\n14:[\"$\",\"$L5a\",null,{\"children\":[\"$\",\"$5b\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@5c\"}]}]\n15:[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L5d\",null,{\"children\":\"$L5e\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L5f\",null,{\"children\":[\"$\",\"$5b\",null,{\"name\":\"Next.Metadata\",\"children\":\"$L60\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}]\n"])</script>
120<script>self.__next_f.push([1,"1b:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"If you already have a Circle client instance, use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createCircleSiwaSignerFromClient\"}],\":\"]}]\n1c:[\"$\",\"$L1a\",null,{\"title\":\"From Existing Client\",\"language\":\"typescript\",\"children\":\"import { initiateDeveloperControlledWalletsClient } from \\\"@circle-fin/developer-controlled-wallets\\\";\\nimport { createCircleSiwaSignerFromClient } from \\\"@buildersgarden/siwa/signer\\\";\\n\\nconst client = initiateDeveloperControlledWalletsClient({\\n apiKey: process.env.CIRCLE_API_KEY!,\\n entitySecret: process.env.CIRCLE_ENTITY_SECRET!,\\n});\\n\\nconst signer = await createCircleSiwaSignerFromClient({\\n client,\\n walletId: process.env.CIRCLE_WALLET_ID!,\\n});\"}]\n"])</script>
120<script>self.__next_f.push([1,"1d:[\"$\",\"div\",null,{\"id\":\"wallet-openfort\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Openfort\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Openfort's backend wallets provide secure key management and account abstraction for AI agents. Install the Openfort Node SDK alongside SIWA:\"}],[\"$\",\"$L19\",null,{\"language\":\"bash\",\"children\":\"npm install @openfort/openfort-node\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Create a signer from your Openfort wallet credentials:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Openfort Signer Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createOpenfortSiwaSigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\n// Create signer - wallet address is fetched automatically from Openfort\\nconst signer = await createOpenfortSiwaSigner({\\n apiKey: process.env.OPENFORT_PROJECT_PUBLISHABLE_KEY!,\\n walletSecret: process.env.OPENFORT_WALLET_SECRET!,\\n accountId: process.env.OPENFORT_BACKEND_WALLET_ACCOUNT_ID!,\\n});\\n\\n// Sign SIWA message\\nconst { message, signature, address } = await signSIWAMessage({\\n domain: \\\"api.example.com\\\",\\n uri: \\\"https://api.example.com/siwa\\\",\\n agentId: 42,\\n agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n chainId: 84532,\\n nonce,\\n issuedAt: new Date().toISOString(),\\n}, signer);\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"If you already have an Openfort client instance, use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createOpenfortSiwaSignerFromClient\"}],\":\"]}],[\"$\",\"$L1a\",null,{\"title\":\"From Existing Client\",\"language\":\"typescript\",\"children\":\"import Openfort from \\\"@openfort/openfort-node\\\";\\nimport { createOpenfortSiwaSignerFromClient } from \\\"@buildersgarden/siwa/signer\\\";\\n\\nconst client = new Openfort(process.env.OPENFORT_PROJECT_PUBLISHABLE_KEY!, {\\n walletSecret: process.env.OPENFORT_WALLET_SECRET!,\\n});\\n\\nconst signer = await createOpenfortSiwaSignerFromClient({\\n client,\\n accountId: process.env.OPENFORT_BACKEND_WALLET_ACCOUNT_ID!,\\n});\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"1e:[\"$\",\"div\",null,{\"id\":\"wallet-privy\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Privy\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Privy's server wallets provide embedded wallet infrastructure for AI agents. Install the Privy Node SDK alongside SIWA:\"}],[\"$\",\"$L19\",null,{\"language\":\"bash\",\"children\":\"npm install @privy-io/node\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Create a signer from your Privy wallet:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Privy Signer Example\",\"language\":\"typescript\",\"children\":\"import { PrivyClient } from \\\"@privy-io/node\\\";\\nimport { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createPrivySiwaSigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\nconst privy = new PrivyClient({\\n appId: process.env.PRIVY_APP_ID!,\\n appSecret: process.env.PRIVY_APP_SECRET!,\\n});\\n\\nconst signer = createPrivySiwaSigner({\\n client: privy,\\n walletId: process.env.PRIVY_WALLET_ID!,\\n walletAddress: process.env.PRIVY_WALLET_ADDRESS! as `0x${string}`,\\n});\\n\\n// Sign SIWA message\\nconst { message, signature, address } = await signSIWAMessage({\\n domain: \\\"api.example.com\\\",\\n uri: \\\"https://api.example.com/siwa\\\",\\n agentId: 42,\\n agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n chainId: 84532,\\n nonce,\\n issuedAt: new Date().toISOString(),\\n}, signer);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"1f:[\"$\",\"div\",null,{\"id\":\"wallet-privatekey\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Private Key (Backend Scripts)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"For server-side agents or scripts with direct private key access:\"}],[\"$\",\"$L1a\",null,{\"title\":\"Private Key Signer Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createLocalAccountSigner } from \\\"@buildersgarden/siwa/signer\\\";\\nimport { privateKeyToAccount } from \\\"viem/accounts\\\";\\n\\nconst account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);\\nconst signer = createLocalAccountSigner(account);\\n\\n// Sign SIWA message\\nconst { message, signature } = await signSIWAMessage({\\n domain: \\\"api.example.com\\\",\\n uri: \\\"https://api.example.com/siwa\\\",\\n agentId: 42,\\n agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n chainId: 84532,\\n nonce,\\n issuedAt: new Date().toISOString(),\\n}, signer);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"20:[\"$\",\"div\",null,{\"id\":\"wallet-keyring\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Keyring Proxy (Self-Hosted, Non-Custodial)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"For AI agents that need secure key isolation, we provide an optional \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"keyring proxy\"}],\" â a separate service that holds the encrypted private key and performs all signing. The agent never touches the key.\"]}],[\"$\",\"$L1a\",null,{\"title\":\"Keyring Proxy Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createKeyringProxySigner } from \\\"@buildersgarden/siwa/signer\\\";\\n\\nconst signer = createKeyringProxySigner({\\n proxyUrl: process.env.KEYRING_PROXY_URL,\\n proxySecret: process.env.KEYRING_PROXY_SECRET,\\n});\\n\\n// Sign SIWA message\\nconst { message, signature } = await signSIWAMessage({\\n domain: \\\"api.example.com\\\",\\n uri: \\\"https://api.example.com/siwa\\\",\\n agentId: 42,\\n agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n chainId: 84532,\\n nonce,\\n issuedAt: new Date().toISOString(),\\n}, signer);\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"The keyring proxy is completely optional. It's useful when you want:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-4 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":\"Key isolation from the agent process (protection against prompt injection)\"}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":\"Optional 2FA via Telegram for transaction approval\"}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":\"Self-hosted, non-custodial key management\"}]]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"See\",\" \",[\"$\",\"a\",null,{\"href\":\"/docs/deploy\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"Deploy\"}],\" \",\"for keyring proxy setup, architecture, and security model.\"]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"21:[\"$\",\"div\",null,{\"id\":\"smart-accounts\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Smart Accounts\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Smart contract wallets (Safe, ZeroDev/Kernel, Coinbase Smart Wallet) work with the same \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createWalletClientSigner\"}],\" â their SDKs expose a standard WalletClient or EIP-1193 provider. The SDK detects the signer type automatically during verification via ERC-1271.\"]}],[\"$\",\"$L1a\",null,{\"title\":\"Smart Account Example\",\"language\":\"typescript\",\"children\":\"import { signSIWAMessage } from \\\"@buildersgarden/siwa\\\";\\nimport { createWalletClientSigner } from \\\"@buildersgarden/siwa/signer\\\";\\nimport { createWalletClient, custom } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\n// Safe example\\nimport Safe from \\\"@safe-global/protocol-kit\\\";\\nconst safe = await Safe.init({ provider, safeAddress });\\nconst walletClient = createWalletClient({\\n chain: baseSepolia,\\n transport: custom(safe.getProvider()),\\n});\\nconst signer = createWalletClientSigner(walletClient);\\n\\n// ZeroDev / Kernel example\\n// const walletClient = kernelClient.toWalletClient();\\n// const signer = createWalletClientSigner(walletClient);\\n\\n// Sign SIWA message â same as any other signer\\nconst { message, signature } = await signSIWAMessage({\\n domain: \\\"api.example.com\\\",\\n uri: \\\"https://api.example.com/siwa\\\",\\n agentId: 42,\\n agentRegistry: \\\"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\\\",\\n chainId: 84532,\\n nonce,\\n issuedAt: new Date().toISOString(),\\n}, signer);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"61:T46d,import { signSIWAMessage } from \"@buildersgarden/siwa\";\n\n// Step 1: Request nonce from server\nconst nonceRes = await fetch(\"https://api.example.com/siwa/nonce\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n address: await signer.getAddress(),\n agentId: 42,\n agentRegistry: \"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\",\n }),\n});\nconst { nonce, issuedAt, expirationTime } = await nonceRes.json();\n\n// Step 2: Sign the SIWA message\nconst { message, signature, address } = await signSIWAMessage({\n domain: \"api.example.com\",\n uri: \"https://api.example.com/siwa\",\n agentId: 42,\n agentRegistry: \"eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e\",\n chainId: 84532,\n nonce,\n issuedAt,\n expirationTime,\n}, signer);\n\n// Step 3: Send to server for verification\nconst verifyRes = await fetch(\"https://api.example.com/siwa/verify\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ message, signature }),\n});\n\nconst { receipt, agentId } = await verifyRes.json();\n// Store the receipt for authenticated API calls"])</script>
120<script>self.__next_f.push([1,"22:[\"$\",\"div\",null,{\"id\":\"signing-siwa\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"SIWA Sign-In\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Build and sign a SIWA message to prove ownership of an ERC-8004 identity. The authentication flow consists of two steps:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-4 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Get a nonce\"}],\" from the server's \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/siwa/nonce\"}],\" endpoint\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Sign and verify\"}],\" by sending the signature to \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/siwa/verify\"}]]}]]}]]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"signSIWAMessage(fields, signer)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"{ message, signature, address }\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Build and sign a SIWA message.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"buildSIWAMessage(fields)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Build a formatted SIWA message string.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa\"}],\".\"]}],[\"$\",\"$L1a\",null,{\"title\":\"Full Authentication Flow\",\"language\":\"typescript\",\"children\":\"$61\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"23:[\"$\",\"div\",null,{\"id\":\"signing-erc8128\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"ERC-8128 Request Signing\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"After SIWA sign-in, sign every outgoing API request with ERC-8128 HTTP Message Signatures.\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"signAuthenticatedRequest(req, receipt, signer, chainId, options?)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Request\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Sign outgoing request with ERC-8128.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"createErc8128Signer(signer, chainId, options?)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EthHttpSigner\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Create ERC-8128 HTTP signer from SIWA Signer.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/erc8128\"}],\".\"]}],[\"$\",\"$L1a\",null,{\"title\":\"Request Signing Example\",\"language\":\"typescript\",\"children\":\"import { signAuthenticatedRequest } from \\\"@buildersgarden/siwa/erc8128\\\";\\n\\nconst request = new Request(\\\"https://api.example.com/action\\\", {\\n method: \\\"POST\\\",\\n headers: { \\\"Content-Type\\\": \\\"application/json\\\" },\\n body: JSON.stringify({ action: \\\"transfer\\\" }),\\n});\\n\\nconst signedRequest = await signAuthenticatedRequest(\\n request,\\n receipt, // from SIWA sign-in\\n signer,\\n 84532\\n);\\n\\nconst response = await fetch(signedRequest);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"24:[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}]\n25:[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"The full SIWA message string.\"}]\n26:[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"signature\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EIP-191 signature hex string.\"}]]}]\n27:[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"expectedDomain\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Must match message domain.\"}]]}]\n28:[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"nonceValid\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"function | object\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"Nonce validator: callback (nonce) =\u003e boolean, \",\"{ nonceToken, secret }\",\" for stateless, or \",\"{ nonceStore }\",\" for store-based replay protection. See \",[\"$\",\"a\",null,{\"href\":\"#nonce-store\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"Nonce Store\"}],\".\"]}]]}]\n29:[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"client\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"PublicClient\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"viem PublicClient for onchain verification.\"}]]}]\n2a:[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"criteria?\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SIWAVerifyCriteria\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Optional criteria to filter agents (see below).\"}]]}]\n2b:[\"$\",\"div\",null,{\"className\":\"mt-4 mb-4\",\"children\":[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground mb-3\",\"children\":\"Criteria Options\"}]}]\n2c:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Use criteria to enforce policies on which agents can authenticate. These are checked during sign-in and encoded into the receipt.\"}]\n"])</script>
120<script>self.__next_f.push([1,"2d:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Criteria\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Criteria\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"allowedSignerTypes\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"('eoa' | 'sca')[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Restrict to EOA-only or allow smart contract accounts.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"mustBeActive\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"boolean\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Require agent metadata.active === true.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"requiredServices\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent must support these services (e.g., 'llm', 'web3').\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"requiredTrust\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent must support these trust models (e.g., 'tee', 'crypto-economic').\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"minScore\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"number\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Minimum reputation score (requires reputationRegistryAddress).\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"minFeedbackCount\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"number\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Minimum feedback count (requires reputationRegistryAddress).\"}]]}],[\"$\",\"tr\",\"6\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"reputationRegistryAddress\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Reputation registry address for score/feedback checks.\"}]]}],[\"$\",\"tr\",\"7\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"custom\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"(agent) =\u003e Promise\u003cboolean\u003e\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Custom validation function with full agent profile.\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"2e:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The result includes \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"signerType\"}],\" and optionally \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"agent\"}],\" (full profile if criteria fetched metadata).\"]}]\n2f:[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Nonce Endpoint Examples\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1\",\"children\":[\"Issue a nonce for the agent to sign. Import \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createSIWANonce\"}],\" from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa\"}],\".\"]}]]}]\n30:[\"$\",\"$L1a\",null,{\"title\":\"Next.js Nonce Endpoint\",\"language\":\"typescript\",\"children\":\"// app/api/siwa/nonce/route.ts\\nimport { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\nimport { corsJson, siwaOptions } from \\\"@buildersgarden/siwa/next\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst client = createPublicClient({\\n chain: baseSepolia,\\n transport: http(process.env.RPC_URL),\\n});\\n\\n// Simple in-memory nonce store (use Redis in production)\\nconst nonceStore = new Map\u003cstring, number\u003e();\\n\\nexport async function POST(req: Request) {\\n const { address, agentId, agentRegistry } = await req.json();\\n\\n const result = await createSIWANonce(\\n { address, agentId, agentRegistry },\\n client,\\n );\\n\\n // Store nonce for verification\\n nonceStore.set(result.nonce, Date.now());\\n\\n return corsJson({\\n nonce: result.nonce,\\n issuedAt: result.issuedAt,\\n expirationTime: result.expirationTime,\\n });\\n}\\n\\nexport { siwaOptions as OPTIONS };\"}]\n31:[\"$\",\"$L1a\",null,{\"title\":\"Express Nonce Endpoint\",\"language\":\"typescript\",\"children\":\"// routes/siwa.ts\\nimport express from \\\"express\\\";\\nimport { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\nimport { siwaCors, siwaJsonParser } from \\\"@buildersgarden/siwa/express\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst router = express.Router();\\nrouter.use(siwaJsonParser());\\nrouter.use(siwaCors());\\n\\nconst client = createPublicClient({\\n chain: baseSepolia,\\n transport: http(process.env.RPC_URL),\\n});\\n\\nconst nonceStore = new Map\u003cstring, number\u003e();\\n\\nrouter.post(\\\"/nonce\\\", async (req, res) =\u003e {\\n const { address, agentId, agentRegistry } = req.body;\\n\\n const result = await createSIWANonce(\\n { address, agentId, agentRegistry },\\n client,\\n );\\n\\n nonceStore.set(result.nonce, Date.now());\\n\\n res.json({\\n nonce: result.nonce,\\n issuedAt: result.issuedAt,\\n expirationTime: result.expirationTime,\\n });\\n});\\n\\nexport default router;\"}]\n32:[\"$\",\"$L1a\",null,{\"title\":\"Hono Nonce Endpoint\",\"language\":\"typescript\",\"children\":\"// src/routes/siwa.ts\\nimport { Hono } from \\\"hono\\\";\\nimport { cors } from \\\"hono/cors\\\";\\nimport { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst app = new Hono();\\n\\napp.use(\\\"*\\\", cors({\\n origin: \\\"*\\\",\\n allowHeaders: [\\\"Content-Type\\\", \\\"X-SIWA-Receipt\\\", \\\"Signature\\\", \\\"Signature-Input\\\", \\\"Content-Digest\\\"],\\n}));\\n\\nconst client = createPublicClient({\\n chain: baseSepolia,\\n transport: http(process.env.RPC_URL),\\n});\\n\\nconst nonceStore = new Map\u003cstring, number\u003e();\\n\\napp.post(\\\"/nonce\\\", async (c) =\u003e {\\n const { address, agentId, agentRegistry } = await c.req.json();\\n\\n const result = await createSIWANonce(\\n { address, agentId, agentRegistry },\\n client,\\n );\\n\\n nonceStore.set(result.nonce, Date.now());\\n\\n return c.json({\\n nonce: result.nonce,\\n issuedAt: result.issuedAt,\\n expirationTime: result.e"])</script>
120<script>self.__next_f.push([1,"xpirationTime,\\n });\\n});\\n\\nexport default app;\"}]\n33:[\"$\",\"$L1a\",null,{\"title\":\"Fastify Nonce Endpoint\",\"language\":\"typescript\",\"children\":\"// src/routes/siwa.ts\\nimport { FastifyPluginAsync } from \\\"fastify\\\";\\nimport { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst client = createPublicClient({\\n chain: baseSepolia,\\n transport: http(process.env.RPC_URL),\\n});\\n\\nconst nonceStore = new Map\u003cstring, number\u003e();\\n\\nconst siwaRoutes: FastifyPluginAsync = async (fastify) =\u003e {\\n fastify.post(\\\"/nonce\\\", async (req) =\u003e {\\n const { address, agentId, agentRegistry } = req.body as {\\n address: string;\\n agentId: number;\\n agentRegistry: string;\\n };\\n\\n const result = await createSIWANonce(\\n { address, agentId, agentRegistry },\\n client,\\n );\\n\\n nonceStore.set(result.nonce, Date.now());\\n\\n return {\\n nonce: result.nonce,\\n issuedAt: result.issuedAt,\\n expirationTime: result.expirationTime,\\n };\\n });\\n};\\n\\nexport default siwaRoutes;\"}]\n34:[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Verify Endpoint Examples\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1\",\"children\":\"Verify the signed message and issue a receipt.\"}]]}]\n62:T5a5,"])</script>
120<script>self.__next_f.push([1,"// app/api/siwa/verify/route.ts\nimport { verifySIWA } from \"@buildersgarden/siwa\";\nimport { createReceipt } from \"@buildersgarden/siwa/receipt\";\nimport { corsJson, siwaOptions } from \"@buildersgarden/siwa/next\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst client = createPublicClient({\n chain: baseSepolia,\n transport: http(process.env.RPC_URL),\n});\n\n// Simple in-memory nonce store (use Redis in production)\nconst nonceStore = new Map\u003cstring, number\u003e();\n\nexport async function POST(req: Request) {\n const { message, signature } = await req.json();\n\n const result = await verifySIWA(\n message,\n signature,\n \"api.example.com\",\n (nonce) =\u003e {\n if (!nonceStore.has(nonce)) return false;\n nonceStore.delete(nonce); // consume nonce\n return true;\n },\n client,\n {\n allowedSignerTypes: [\"eoa\", \"sca\"],\n mustBeActive: true,\n requiredServices: [\"llm\"],\n }\n );\n\n if (!result.valid) {\n return corsJson({ error: result.error }, { status: 401 });\n }\n\n // Issue receipt for authenticated requests\n const { receipt } = createReceipt({\n address: result.address,\n agentId: result.agentId,\n agentRegistry: result.agentRegistry,\n chainId: result.chainId,\n signerType: result.signerType,\n }, { secret: process.env.RECEIPT_SECRET! });\n\n return corsJson({ receipt, agentId: result.agentId });\n}\n\nexport { siwaOptions as OPTIONS };"])</script>
120<script>self.__next_f.push([1,"35:[\"$\",\"$L1a\",null,{\"title\":\"Next.js Verify Endpoint\",\"language\":\"typescript\",\"children\":\"$62\"}]\n63:T5b8,"])</script>
120<script>self.__next_f.push([1,"// routes/siwa.ts (add to same router as nonce)\nimport { verifySIWA } from \"@buildersgarden/siwa\";\nimport { createReceipt } from \"@buildersgarden/siwa/receipt\";\nimport { siwaCors, siwaJsonParser } from \"@buildersgarden/siwa/express\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst router = express.Router();\nrouter.use(siwaJsonParser());\nrouter.use(siwaCors());\n\nconst client = createPublicClient({\n chain: baseSepolia,\n transport: http(process.env.RPC_URL),\n});\n\n// Simple in-memory nonce store (use Redis in production)\nconst nonceStore = new Map\u003cstring, number\u003e();\n\nrouter.post(\"/verify\", async (req, res) =\u003e {\n const { message, signature } = req.body;\n\n const result = await verifySIWA(\n message,\n signature,\n \"api.example.com\",\n (nonce) =\u003e {\n if (!nonceStore.has(nonce)) return false;\n nonceStore.delete(nonce);\n return true;\n },\n client,\n {\n allowedSignerTypes: [\"eoa\", \"sca\"],\n mustBeActive: true,\n requiredServices: [\"llm\"],\n }\n );\n\n if (!result.valid) {\n return res.status(401).json({ error: result.error });\n }\n\n const { receipt } = createReceipt({\n address: result.address,\n agentId: result.agentId,\n agentRegistry: result.agentRegistry,\n chainId: result.chainId,\n signerType: result.signerType,\n }, { secret: process.env.RECEIPT_SECRET! });\n\n res.json({ receipt, agentId: result.agentId });\n});\n\nexport default router;"])</script>
120<script>self.__next_f.push([1,"36:[\"$\",\"$L1a\",null,{\"title\":\"Express Verify Endpoint\",\"language\":\"typescript\",\"children\":\"$63\"}]\n64:T57f,"])</script>
120<script>self.__next_f.push([1,"// src/routes/siwa.ts (add to same app as nonce)\nimport { verifySIWA } from \"@buildersgarden/siwa\";\nimport { createReceipt } from \"@buildersgarden/siwa/receipt\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst app = new Hono();\n\napp.use(\"*\", cors({\n origin: \"*\",\n allowHeaders: [\"Content-Type\", \"X-SIWA-Receipt\", \"Signature\", \"Signature-Input\", \"Content-Digest\"],\n}));\n\nconst client = createPublicClient({\n chain: baseSepolia,\n transport: http(process.env.RPC_URL),\n});\n\nconst nonceStore = new Map\u003cstring, number\u003e();\n\napp.post(\"/verify\", async (c) =\u003e {\n const { message, signature } = await c.req.json();\n\n const result = await verifySIWA(\n message,\n signature,\n \"api.example.com\",\n (nonce) =\u003e {\n if (!nonceStore.has(nonce)) return false;\n nonceStore.delete(nonce);\n return true;\n },\n client,\n {\n allowedSignerTypes: [\"eoa\", \"sca\"],\n mustBeActive: true,\n requiredServices: [\"llm\"],\n }\n );\n\n if (!result.valid) {\n return c.json({ error: result.error }, 401);\n }\n\n const { receipt } = createReceipt({\n address: result.address,\n agentId: result.agentId,\n agentRegistry: result.agentRegistry,\n chainId: result.chainId,\n signerType: result.signerType,\n }, { secret: process.env.RECEIPT_SECRET! });\n\n return c.json({ receipt, agentId: result.agentId });\n});\n\nexport default app;"])</script>
120<script>self.__next_f.push([1,"37:[\"$\",\"$L1a\",null,{\"title\":\"Hono Verify Endpoint\",\"language\":\"typescript\",\"children\":\"$64\"}]\n65:T58c,"])</script>
120<script>self.__next_f.push([1,"// src/routes/siwa.ts (add to same plugin as nonce)\nimport { verifySIWA } from \"@buildersgarden/siwa\";\nimport { createReceipt } from \"@buildersgarden/siwa/receipt\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst client = createPublicClient({\n chain: baseSepolia,\n transport: http(process.env.RPC_URL),\n});\n\nconst nonceStore = new Map\u003cstring, number\u003e();\n\nconst siwaRoutes: FastifyPluginAsync = async (fastify) =\u003e {\n fastify.post(\"/verify\", async (req, reply) =\u003e {\n const { message, signature } = req.body as { message: string; signature: string };\n\n const result = await verifySIWA(\n message,\n signature,\n \"api.example.com\",\n (nonce) =\u003e {\n if (!nonceStore.has(nonce)) return false;\n nonceStore.delete(nonce);\n return true;\n },\n client,\n {\n allowedSignerTypes: [\"eoa\", \"sca\"],\n mustBeActive: true,\n requiredServices: [\"llm\"],\n }\n );\n\n if (!result.valid) {\n return reply.status(401).send({ error: result.error });\n }\n\n const { receipt } = createReceipt({\n address: result.address,\n agentId: result.agentId,\n agentRegistry: result.agentRegistry,\n chainId: result.chainId,\n signerType: result.signerType,\n }, { secret: process.env.RECEIPT_SECRET! });\n\n return { receipt, agentId: result.agentId };\n });\n};\n\nexport default siwaRoutes;"])</script>
120<script>self.__next_f.push([1,"38:[\"$\",\"$L1a\",null,{\"title\":\"Fastify Verify Endpoint\",\"language\":\"typescript\",\"children\":\"$65\"}]\n"])</script>
120<script>self.__next_f.push([1,"39:[\"$\",\"div\",null,{\"id\":\"verify-erc8128\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"ERC-8128 Request Verification\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Verify incoming ERC-8128 signed requests from authenticated agents.\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifyAuthenticatedRequest(req, options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"AuthResult\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Verify incoming signed request.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/erc8128\"}],\". Options accept \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"allowedSignerTypes\"}],\" for policy enforcement. The verified agent includes a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"signerType\"}],\" field.\"]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"3a:[\"$\",\"div\",null,{\"id\":\"verify-receipts\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Receipts\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Stateless HMAC-signed tokens issued after successful SIWA verification. The agent includes the receipt in subsequent requests, and the server verifies it.\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Function\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Function\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"createReceipt(payload, options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"{ receipt, expiresAt }\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Create an HMAC-signed receipt.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifyReceipt(receipt, secret)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ReceiptPayload | null\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Verify and decode. Returns null if invalid.\"}]]}]]}]]}]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Payload Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Payload Field\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"address\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent wallet address.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"agentId\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"number\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ERC-8004 token ID.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"signerType\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SignerType?\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Optional: 'eoa' or 'sca'.\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/receipt\"}],\".\"]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"3b:[\"$\",\"div\",null,{\"id\":\"verify-wrappers\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Server Middleware\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Drop-in middleware for popular frameworks. Each handles ERC-8128 verification, receipt checking, and CORS.\"}],[\"$\",\"div\",null,{\"className\":\"rounded-lg border border-accent/30 bg-accent/5 px-4 py-3 mb-6\",\"children\":[\"$\",\"p\",null,{\"className\":\"text-sm text-muted leading-relaxed\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent\",\"children\":\"Note:\"}],\" \",\"ERC-8004 criteria (reputation, services, trust models) are checked during SIWA sign-in via\",\" \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verifySIWA()\"}],\". The middleware below verifies ERC-8128 signatures on subsequent requests â it accepts\",\" \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"allowedSignerTypes\"}],\" and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verifyOnchain\"}],\" options for per-request policy.\"]}]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Option\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Option\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"receiptSecret\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"HMAC secret for receipt verification. Defaults to RECEIPT_SECRET env.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"allowedSignerTypes\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"('eoa' | 'sca')[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Restrict to EOA-only or SCA-only agents.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifyOnchain\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"boolean\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Re-check ownerOf on every request (slower but more secure).\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"rpcUrl\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RPC URL for onchain verification.\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"publicClient\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"PublicClient\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"viem PublicClient for ERC-1271 smart account signatures.\"}]]}]]}]]}]}],[\"$\",\"div\",null,{\"id\":\"verify-wrappers-next\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Next.js (App Router)\"}],\"$L66\"]}],\"$L67\",\"$L68\",\"$L69\",\"$L6a\",\"$L6b\",\"$L6c\",\"$L6d\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"3c:[\"$\",\"div\",null,{\"id\":\"nonce-store\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Nonce Store\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Pluggable server-side nonce tracking for replay protection. The SDK ships built-in adapters for Memory, Redis, Cloudflare KV, and any SQL database â no extra dependencies, you bring your own client.\"}]]}]\n"])</script>
120<script>self.__next_f.push([1,"3d:[\"$\",\"div\",null,{\"id\":\"nonce-why\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Why Nonces Matter\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"A SIWA message is valid for its entire TTL window (default 5 minutes). Without server-side tracking, an attacker who intercepts a signed message can \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"replay\"}],\" it â submitting the same signature multiple times to authenticate as the agent.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"A nonce store solves this by recording every issued nonce and consuming it on first use. Once consumed, the nonce is deleted and any replay attempt is rejected.\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"The SDK provides three nonce validation strategies:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Callback\"}],\" â \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"(nonce) =\u003e boolean\"}],\": you manage nonce storage yourself\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Stateless token\"}],\" â \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"{ nonceToken, secret }\"}],\": HMAC-signed token, no server storage needed (but replayable within TTL)\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Nonce store\"}],\" â \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"{ nonceStore }\"}],\": server-side tracking with exactly-once consumption (recommended for production)\"]}]]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"SIWANonceStore\"}],\" interface:\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"interface SIWANonceStore {\\n /** Store an issued nonce. Returns true on success, false if already exists. */\\n issue(nonce: string, ttlMs: number): Promise\u003cboolean\u003e;\\n /** Atomically check-and-delete a nonce. Returns true if it existed. */\\n consume(nonce: string): Promise\u003cboolean\u003e;\\n}\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Wire the store into both \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"createSIWANonce\"}],\" (issue) and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verifySIWA\"}],\" (consume):\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createSIWANonce, verifySIWA } from \\\"@buildersgarden/siwa\\\";\\nimport { createMemorySIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\nconst nonceStore = createMemorySIWANonceStore();\\n\\n// Nonce endpoint â issue\\nconst result = await createSIWANonce(params, client, { nonceStore });
120\\n\\n// Verify endpoint â consume\\nconst verification = await verifySIWA(\\n message, signature, domain,\\n { nonceStore },\\n client,\\n);\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"3e:[\"$\",\"div\",null,{\"id\":\"nonce-memory\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Memory (Default)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"In-memory store using a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Map\"}],\" with TTL-based expiry. Suitable for single-process servers. Nonces are lost on restart.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createMemorySIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\nconst nonceStore = createMemorySIWANonceStore();\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"3f:[\"$\",\"div\",null,{\"id\":\"nonce-redis\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Redis\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Redis-backed store using \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"SET ... PX ttl NX\"}],\" for atomic issue and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"DEL\"}],\" for atomic consume. Works with any Redis client that implements \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"set()\"}],\" and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"del()\"}],\".\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createRedisSIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\n// ioredis (works out of the box)\\nimport Redis from \\\"ioredis\\\";\\nconst redis = new Redis();\\nconst nonceStore = createRedisSIWANonceStore(redis);\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"For \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"node-redis v4\"}],\", wrap with a small adapter since its \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"set()\"}],\" signature differs:\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createClient } from \\\"redis\\\";\\nimport { createRedisSIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\nconst client = createClient(); await client.connect();\\n\\nconst nonceStore = createRedisSIWANonceStore({\\n set: (...args: unknown[]) =\u003e\\n client\\n .set(args[0] as string, args[1] as string, {\\n PX: args[3] as number,\\n NX: true,\\n })\\n .then((r) =\u003e r ?? null),\\n del: (key: unknown) =\u003e client.del(key as string),\\n});\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"40:[\"$\",\"div\",null,{\"id\":\"nonce-kv\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Cloudflare KV\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Cloudflare Workers KV-backed store. Uses \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"put\"}],\" with \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"expirationTtl\"}],\" for auto-expiry. The consume path does a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"get\"}],\" + \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"delete\"}],\" â not fully atomic, but acceptable for random nonces.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createKVSIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\n\\n// In a Cloudflare Worker\\nexport default {\\n async fetch(request: Request, env: Env) {\\n const nonceStore = createKVSIWANonceStore(env.SIWA_NONCES);\\n // use with createSIWANonce / verifySIWA\\n },\\n};\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Bind a KV namespace called \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"SIWA_NONCES\"}],\" in your \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"wrangler.toml\"}],\":\"]}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"[[kv_namespaces]]\\nbinding = \\\"SIWA_NONCES\\\"\\nid = \\\"\u003cyour-kv-namespace-id\u003e\\\"\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"41:[\"$\",\"div\",null,{\"id\":\"nonce-database\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Database\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"For databases, implement \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"SIWANonceStore\"}],\" directly â it's just two methods. No factory needed.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Schema\"}],\" â create a table with a unique nonce column and an expiry timestamp:\"]}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"CREATE TABLE siwa_nonces (\\n nonce VARCHAR(64) PRIMARY KEY,\\n expires_at TIMESTAMPTZ NOT NULL\\n);\\n-- Optional: periodic cleanup of expired rows\\n-- DELETE FROM siwa_nonces WHERE expires_at \u003c NOW();\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Prisma\"}],\":\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import type { SIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";
120\\n\\nconst nonceStore: SIWANonceStore = {\\n async issue(nonce, ttlMs) {\\n try {\\n await prisma.siwaNonce.create({\\n data: { nonce, expiresAt: new Date(Date.now() + ttlMs) },\\n });\\n return true;\\n } catch (e: any) {\\n if (e.code === \\\"P2002\\\") return false; // unique constraint\\n throw e;\\n }\\n },\\n async consume(nonce) {\\n try {\\n await prisma.siwaNonce.delete({ where: { nonce } });\\n return true;\\n } catch {\\n return false;\\n }\\n },\\n};\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Drizzle\"}],\":\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import type { SIWANonceStore } from \\\"@buildersgarden/siwa/nonce-store\\\";\\nimport { eq, and, gt } from \\\"drizzle-orm\\\";\\nimport { siwaNonces } from \\\"./schema\\\";\\n\\nconst nonceStore: SIWANonceStore = {\\n async issue(nonce, ttlMs) {\\n try {\\n await db.insert(siwaNonces).values({\\n nonce,\\n expiresAt: new Date(Date.now() + ttlMs),\\n });\\n return true;\\n } catch (e: any) {\\n if (e.code === \\\"23505\\\") return false; // unique violation\\n throw e;\\n }\\n },\\n async consume(nonce) {\\n const result = await db\\n .delete(siwaNonces)\\n .where(\\n and(\\n eq(siwaNonces.nonce, nonce),\\n gt(siwaNonces.expiresAt, new Date()),\\n ),\\n );\\n return (result.rowCount ?? 0) \u003e 0;\\n },\\n};\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"42:[\"$\",\"div\",null,{\"id\":\"captcha-how\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Captcha (Reverse CAPTCHA)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"SIWA includes a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"reverse CAPTCHA\"}],\" â inspired by \",[\"$\",\"a\",null,{\"href\":\"https://github.com/MoltCaptcha/MoltCaptcha\",\"className\":\"text-accent hover:underline\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"children\":\"MoltCaptcha\"}],\" â that proves an entity \",[\"$\",\"em\",null,{\"children\":\"is\"}],\" an AI agent, not a human. Challenges exploit how LLMs generate text in a single autoregressive pass, satisfying multiple constraints simultaneously, while humans must iterate.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"The server generates a challenge with constraints the agent must satisfy in its response text â line count, sum of ASCII values of first characters, word count, character at a specific position, and total character count. Higher difficulty levels add more constraints with tighter time limits.\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"Two integration points:\"}],[\"$\",\"ul\",null,{\"className\":\"space-y-2 mb-6 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Sign-in flow\"}],\" â server requires captcha before issuing a nonce\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"text-accent shrink-0\",\"children\":\"â¢\"}],[\"$\",\"span\",null,{\"children\":[[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"Per-request\"}],\" â middleware randomly challenges agents during authenticated API calls (server-defined policy/probability)\"]}]]}]]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"43:[\"$\",\"div\",null,{\"id\":\"captcha-signin\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Sign-In Captcha\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Add \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaPolicy\"}],\" and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaOptions\"}],\" to your nonce endpoint. The policy function receives the agent's identity and returns a difficulty level or \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"null\"}],\" to skip.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { createSIWANonce } from \\\"@buildersgarden/siwa\\\";\\n\\nconst result = await createSIWANonce(\\n { address, agentId, agentRegistry, challengeResponse },\\n client,\\n {\\n secret: SIWA_SECRET,\\n captchaPolicy: async ({ address }) =\u003e {\\n const known = await db.agents.exists(address);\\n return known ? null : 'medium'; // challenge unknown agents\\n },\\n captchaOptions: { secret: SIWA_SECRET },\\n },\\n);\\n\\n// result.status is 'captcha_required' | 'nonce_issued' | SIWAResponse\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Agent-side: use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"solveCaptchaChallenge()\"}],\" to detect and solve in one step.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { solveCaptchaChallenge } from \\\"@buildersgarden/siwa/captcha\\\";\\n\\nconst res = await fetch(\\\"/api/siwa/nonce\\\", {\\n method: \\\"POST\\\",\\n body: JSON.stringify({ address, agentId, agentRegistry }),\\n});\\nconst data = await res.json();\\n\\nconst captcha = await solveCaptchaChallenge(data, async (challenge) =\u003e {\\n // LLM generates text satisfying all constraints in a single pass\\n // Your LLM generates text satisfying all constraints in one pass.\\n // Use any provider (Anthropic, OpenAI, etc.) â just return a string.\\n return await generateText(challenge);\\n});\\n\\nif (captcha.solved) {\\n // Retry with challengeResponse\\n await fetch(\\\"/api/siwa/nonce\\\", {\\n method: \\\"POST\\\",\\n body: JSON.stringify({ ...params, challengeResponse: captcha.challengeResponse }),\\n });\\n}\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"44:[\"$\",\"div\",null,{\"id\":\"captcha-perrequest\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Per-Request Captcha\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Add \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaPolicy\"}],\" to middleware for random spot-checks on authenticated requests.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"// Next.js\\nexport const POST = withSiwa(handler, {\\n captchaPolicy: ({ request }) =\u003e {\\n if (request?.url.includes('/transfer') \u0026\u0026 Math.random() \u003c 0.05)\\n return 'hard';\\n return null;\\n },\\n captchaOptions: { secret: process.env.SIWA_SECRET! },\\n});\\n\\n// Express\\napp.use(siwaMiddleware({\\n captchaPolicy: () =\u003e Math.random() \u003c 0.05 ? 'easy' : null,\\n captchaOptions: { secret: SIWA_SECRET },\\n}));\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Agent-side: use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"retryWithCaptcha()\"}],\" to detect a 401 captcha challenge, solve it, re-sign with ERC-8128, and get a ready-to-send retry request.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import { signAuthenticatedRequest, retryWithCaptcha } from \\\"@buildersgarden/siwa/erc8128\\\";\\n\\nconst url = \\\"https://api.example.com/action\\\";\\nconst body = JSON.stringify({ key: \\\"value\\\" });\\n\\n// Sign and send\\nconst signed = await signAuthenticatedRequest(\\n new Request(url, { method: \\\"POST\\\", body }), receipt, signer, chainId,\\n);\\nconst response = await fetch(signed);\\n\\n// Detect + solve + re-sign if captcha required\\nconst result = await retryWithCaptcha(\\n response,\\n new Request(url, { method: \\\"POST\\\", body }), // fresh request\\n receipt, signer, chainId,\\n async (challenge) =\u003e generateText(challenge), // your LLM solver\\n);\\n\\nif (result.retry) {\\n const retryResponse = await fetch(result.request);\\n}\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"45:[\"$\",\"div\",null,{\"id\":\"captcha-difficulty\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Difficulty Levels \u0026 Configuration\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Level\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Level\"}],[\"$\",\"th\",\"Time Limit\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Time Limit\"}],[\"$\",\"th\",\"Constraints\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Constraints\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"easy\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"30s\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Line count + ASCII sum of first chars\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"medium\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"20s\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"+ word count\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"hard\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"15s\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"+ character at specific position\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"extreme\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"10s\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"+ total character count\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"All verification behavior is configurable via \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaOptions.verify\"}],\":\"]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Option\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Option\"}],[\"$\",\"th\",\"Default\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Default\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"useServerTiming\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"true\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Use server wall-clock time instead of trusting the agent's solvedAt.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"timingToleranceSeconds\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"2\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Extra seconds added to time limit for network latency.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"asciiTolerance\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"0\"}],\"$L6e\"]}],\"$L6f\",\"$L70\"]}]]}]}],\"$L71\",\"$L72\",\"$L73\",\"$L74\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"46:[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Required\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server to Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base64-encoded JSON with accepted payment options. Sent with 402 responses.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Signature\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent to Server\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base64-encoded signed payment payload from the agent.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Response\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server to Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base64-encoded settlement result with transaction hash.\"}]]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"47:[\"$\",\"div\",null,{\"id\":\"x402-server\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Server Setup\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Three things are needed to enable x402 on a route: a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"facilitator client\"}],\" (verifies and settles payments), a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"resource description\"}],\", and an \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"accepts array\"}],\" listing payment options.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import {\\n createFacilitatorClient,\\n type X402Config,\\n} from \\\"@buildersgarden/siwa/x402\\\";\\n\\n// 1. Create facilitator client\\nconst facilitator = createFacilitatorClient({\\n url: \\\"https://x402-facilitator.example.com\\\",\\n});\\n\\n// 2. Define x402 config\\nconst x402: X402Config = {\\n facilitator,\\n resource: {\\n url: \\\"/api/premium\\\",\\n description: \\\"Premium data access\\\",\\n },\\n accepts: [\\n {\\n scheme: \\\"exact\\\",\\n network: \\\"eip155:84532\\\", // Base Sepolia\\n amount: \\\"1000000\\\", // 1 USDC (6 decimals)\\n asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n payTo: \\\"0xYourAddress\\\",\\n maxTimeoutSeconds: 60,\\n },\\n ],\\n};\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Pass the \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"x402\"}],\" config to any framework middleware. Routes without \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"x402\"}],\" remain SIWA-only (free).\"]}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"48:[\"$\",\"div\",null,{\"id\":\"x402-sessions\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Sessions (Pay-Once)\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"By default, every request requires a new payment. Add \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"session\"}],\" to the x402 config to enable \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"pay-once mode\"}],\": the agent pays on the first request and subsequent requests within the TTL window pass through without payment.\"]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Sessions are keyed by \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"(address, resource.url)\"}],\" â different agents and different routes are isolated from each other.\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"import {\\n createFacilitatorClient,\\n createMemoryX402SessionStore,\\n} from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst facilitator = createFacilitatorClient({\\n url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\n// In-memory store (use Redis/DB in production)\\nconst sessionStore = createMemoryX402SessionStore();\\n\\n// Pass to any middleware\\nconst x402Config = {\\n facilitator,\\n resource: { url: \\\"/api/premium\\\", description: \\\"Premium access\\\" },\\n accepts: [/* ... */],\\n session: {\\n store: sessionStore,\\n ttl: 3600_000, // 1 hour\\n },\\n};\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"On the first request, the agent pays and the middleware stores a session. On subsequent requests from the same agent to the same resource, the session is found and payment is skipped. After TTL expiry, payment is required again.\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"For production, implement the \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"X402SessionStore\"}],\" interface with a shared store:\"]}],[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"interface X402SessionStore {\\n get(address: string, resource: string): Promise\u003cX402Session | null\u003e;\\n set(address: string, resource: string, session: X402Session, ttlMs: number): Promise\u003cvoid\u003e;\\n}\\n\\ninterface X402Session {\\n paidAt: number;\\n txHash?: string;\\n}\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"49:[\"$\",\"div\",null,{\"id\":\"x402-config\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Config Reference\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Field\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"facilitator\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"FacilitatorClient\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Client for payment verification and settlement.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"resource\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ResourceInfo\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"The resource being paid for: { url, description? }.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"accepts\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"PaymentRequirements[]\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Array of accepted payment options.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"session?\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"X402SessionConfig\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Optional pay-once session: { store, ttl }.\"}]]}]]}]]}]}],[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"PaymentRequirements\"}]}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Field\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"sc
120heme\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"Payment scheme (e.g. \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"\\\"exact\\\"\"}],\").\"]}]]}],\"$L75\",\"$L76\",\"$L77\",\"$L78\",\"$L79\"]}]]}]}],\"$L7a\",\"$L7b\",\"$L7c\",\"$L7d\",\"$L7e\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"4a:[\"$\",\"div\",null,{\"id\":\"x402-middleware\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Middleware\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Each framework wrapper accepts an optional \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"x402\"}],\" field. When set, both SIWA authentication \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"and\"}],\" a valid payment are required. The verified payment is available in the handler.\"]}],[\"$\",\"div\",null,{\"id\":\"x402-express\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Express\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/express\"}],\". Payment is available on \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"req.payment\"}],\".\"]}]]}],[\"$\",\"$L1a\",null,{\"title\":\"Express x402 Example\",\"language\":\"typescript\",\"children\":\"import express from \\\"express\\\";\\nimport { siwaMiddleware, siwaJsonParser, siwaCors } from \\\"@buildersgarden/siwa/express\\\";\\nimport { createFacilitatorClient } from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst app = express();\\napp.use(siwaJsonParser());\\napp.use(siwaCors({ x402: true })); // expose x402 headers in CORS\\n\\nconst facilitator = createFacilitatorClient({\\n url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\napp.post(\\n \\\"/api/premium\\\",\\n siwaMiddleware({\\n x402: {\\n facilitator,\\n resource: { url: \\\"/api/premium\\\", description: \\\"Premium endpoint\\\" },\\n accepts: [\\n {\\n scheme: \\\"exact\\\",\\n network: \\\"eip155:84532\\\",\\n amount: \\\"1000000\\\",\\n asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n payTo: \\\"0xYourAddress\\\",\\n },\\n ],\\n },\\n }),\\n (req, res) =\u003e {\\n // req.agent â verified SIWA identity\\n // req.payment â { scheme, network, amount, asset, payTo, txHash }\\n res.json({ agent: req.agent, txHash: req.payment?.txHash });\\n },\\n);\"}],[\"$\",\"div\",null,{\"id\":\"x402-next\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Next.js\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/next\"}],\". Payment is the 3rd argument to the handler.\"]}]]}],[\"$\",\"$L1a\",null,{\"title\":\"Next.js x402 Example\",\"language\":\"typescript\",\"children\":\"// app/api/premium/route.ts\\nimport { withSiwa, siwaOptions } from \\\"@buildersgarden/siwa/next\\\";\\nimport { createFacilitatorClient } from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst facilitator = createFacilitatorClient({\\n url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\nexport const POST = withSiwa(\\n async (agent, req, payment) =\u003e {\\n // agent â verified SIWA identity\\n // payment â { scheme, network, amount, asset, payTo, txHash } or undefined\\n return { agent, txHash: payment?.txHash };\\n },\\n {\\n x402: {\\n facilitator,\\n resource: { url: \\\"/api/premium\\\", description: \\\"Premium endpoint\\\" },\\n accepts: [\\n {\\n scheme: \\\"exact\\\",\\n network: \\\"eip155:84532\\\",\\n amount: \\\"1000000\\\",\\n asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n payTo: \\\"0xYourAddress\\\",\\n },\\n ],\\n },\\n },\\n);
120\\n\\n// OPTIONS handler with x402 CORS headers\\nexport const OPTIONS = () =\u003e siwaOptions({ x402: true });\"}],\"$L7f\",\"$L80\",\"$L81\",\"$L82\"]}]\n"])</script>
120<script>self.__next_f.push([1,"83:T588,"])</script>
120<script>self.__next_f.push([1,"import {\n encodeX402Header,\n decodeX402Header,\n type PaymentRequired,\n type PaymentPayload,\n} from \"@buildersgarden/siwa/x402\";\nimport { signAuthenticatedRequest } from \"@buildersgarden/siwa/erc8128\";\n\n// 1. Make initial request (will get 402)\nconst signedRequest = await signAuthenticatedRequest(\n new Request(\"https://api.example.com/premium\", { method: \"POST\" }),\n receipt,\n signer,\n 84532,\n);\n\nconst res = await fetch(signedRequest);\n\nif (res.status === 402) {\n // 2. Decode payment requirements\n const header = res.headers.get(\"Payment-Required\");\n const { accepts, resource } = decodeX402Header\u003cPaymentRequired\u003e(header!);\n\n // 3. Pick a payment option and construct payload\n const option = accepts[0];\n const payload: PaymentPayload = {\n signature: \"0x...\", // sign the payment with your wallet\n payment: {\n scheme: option.scheme,\n network: option.network,\n amount: option.amount,\n asset: option.asset,\n payTo: option.payTo,\n },\n resource,\n };\n\n // 4. Retry with payment header\n const retryRequest = await signAuthenticatedRequest(\n new Request(\"https://api.example.com/premium\", {\n method: \"POST\",\n headers: {\n \"Payment-Signature\": encodeX402Header(payload),\n },\n }),\n receipt,\n signer,\n 84532,\n );\n\n const paidRes = await fetch(retryRequest);\n // paidRes.headers.get(\"Payment-Response\") contains { txHash, ... }\n}"])</script>
120<script>self.__next_f.push([1,"4b:[\"$\",\"div\",null,{\"id\":\"x402-agent\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Agent-Side\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"When an agent receives a \",[\"$\",\"strong\",null,{\"className\":\"text-foreground\",\"children\":\"402\"}],\" response, it should:\"]}],[\"$\",\"ol\",null,{\"className\":\"space-y-2 mb-4 text-sm leading-relaxed text-muted list-none\",\"children\":[[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"1.\"}],[\"$\",\"span\",null,{\"children\":[\"Read the \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Required\"}],\" header and decode the payment options.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"2.\"}],[\"$\",\"span\",null,{\"children\":[\"Construct a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"PaymentPayload\"}],\" with the signed payment.\"]}]]}],[\"$\",\"li\",null,{\"className\":\"flex gap-3\",\"children\":[[\"$\",\"span\",null,{\"className\":\"font-mono font-semibold text-accent shrink-0\",\"children\":\"3.\"}],[\"$\",\"span\",null,{\"children\":[\"Encode it as a \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"Payment-Signature\"}],\" header and retry the request.\"]}]]}]]}],[\"$\",\"$L1a\",null,{\"title\":\"Agent Payment Flow\",\"language\":\"typescript\",\"children\":\"$83\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"4c:[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"getReputation(agentId, options)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ReputationSummary\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Read agent reputation.\"}]]}]\n4d:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/registry\"}],\".\"]}]\n4e:[\"$\",\"tr\",\"7\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"chainId\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EIP-155 chain ID (numeric). Must match the chain in agentRegistry.\"}]]}]\n4f:[\"$\",\"tr\",\"8\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"nonce\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server-generated, \u003e= 8 alphanumeric chars.\"}]]}]\n50:[\"$\",\"tr\",\"9\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"issuedAt\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Yes\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RFC 3339 datetime.\"}]]}]\n51:[\"$\",\"tr\",\"10\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"expirationTime\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"No\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RFC 3339 datetime.\"}]]}]\n52:[\"$\",\"tr\",\"11\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"notBefore\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"No\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"RFC 3339 datetime.\"}]]}]\n53:[\"$\",\"tr\",\"12\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"requestId\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"No\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Opaque request identifier.\"}]]}]\n54:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"See \",[\"$\",\"a\",null,{\"href\":\"#contracts-format\",\"className\":\"text-accent underline underline-offset-4 decoration-accent/40 hover:decoration-accent transition-colors duration-200\",\"children\":\"Address Formatting Standards\"}],\" for details on CAIP-10, EIP-55, and EIP-155.\"]}]\n"])</script>
120<script>self.__next_f.push([1,"55:[\"$\",\"div\",null,{\"id\":\"protocol-vs-siwe\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"SIWA vs SIWE\"}],[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Aspect\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Aspect\"}],[\"$\",\"th\",\"SIWE (EIP-4361)\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"SIWE (EIP-4361)\"}],[\"$\",\"th\",\"SIWA\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"SIWA\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Purpose\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Human wallet auth\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent identity auth\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Identity proof\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Owns an Ethereum address\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Owns an ERC-8004 agent NFT\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Onchain check\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"None required\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"ownerOf(agentId) REQUIRED\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Extra fields\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"None\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"agentId, agentRegistry\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Signing\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EIP-191\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"EIP-191 (same)\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Message prefix\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"...your Ethereum account\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"...your Agent account\"}]]}]]}]]}]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"57:[\"$\",\"div\",null,{\"id\":\"contracts-format\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Address Formatting Standards\"}],[[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"SIWA uses standardized address formats from the blockchain ecosystem:\"}],[\"$\",\"div\",null,{\"className\":\"mt-4 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"CAIP-10: Agent Registry Reference\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1 mb-3\",\"children\":[[\"$\",\"a\",null,{\"href\":\"https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent hover:underline\",\"children\":\"CAIP-10\"}],\" (Chain Agnostic Improvement Proposal) defines a standard way to reference blockchain accounts across different networks.\"]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"agentRegistry\"}],\" field uses CAIP-10 format to uniquely identify the ERC-8004 Identity Registry contract on a specific chain:\"]}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"{namespace}:{chainId}:{contractAddress}\\n\\nFormat breakdown:\\n namespace = \\\"eip155\\\" (EVM-compatible chains per EIP-155)\\n chainId = numeric chain identifier (e.g., 8453 for Base)\\n contractAddress = EIP-55 checksummed contract address\\n\\nExamples:\\n eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (Base mainnet)\\n eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e (Base Sepolia)\\n eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (Ethereum mainnet)\"}],[\"$\",\"div\",null,{\"className\":\"mt-6 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"EIP-55: Checksummed Addresses\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1 mb-3\",\"children\":[[\"$\",\"a\",null,{\"href\":\"https://eips.ethereum.org/EIPS/eip-55\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent hover:underline\",\"children\":\"EIP-55\"}],\" defines mixed-case checksum encoding for Ethereum addresses.\"]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"All wallet addresses (\",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"address\"}],\" field) must be EIP-55 checksummed. This provides error detection for typos:\"]}],[\"$\",\"$L19\",null,{\"language\":\"text\",\"children\":\"Correct (checksummed): 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0\\nIncorrect (lowercase): 0x742d35cc6634c0532925a3b844bc9e7595f0beb0\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Most libraries (viem, ethers.js) automatically return checksummed addresses. You can use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"getAddress()\"}],\" from viem to ensure proper formatting.\"]}],[\"$\",\"div\",null,{\"className\":\"mt-6 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"EIP-155: Chain IDs\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mt-1 mb-3\",\"children\":[[\"$\",\"a\",null,{\"href\":\"https://eips.ethereum.org/EIPS/eip-155\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent hover:underline\",\"children\":\"EIP-155\"}],\" introduced chain IDs to prevent replay attacks across different networks.\"]}]]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"The \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"chainId\"}],\" field identifies which blockchain network the agent is registered on. Common chain IDs:\"]}],\"$L84\"]]}]\n"])</script>
120<script>self.__next_f.push([1,"58:[\"$\",\"div\",null,{\"id\":\"contracts-rpc\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Public RPC Endpoints\"}],[[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Chain\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain\"}],[\"$\",\"th\",\"RPC URL\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"RPC URL\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://mainnet.base.org\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://rpc.sepolia.org\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://sepolia.base.org\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Linea Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://rpc.sepolia.linea.build\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Polygon Amoy\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"https://rpc-amoy.polygon.technology\"}]]}]]}]]}]}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":\"For production, use a provider like Alchemy or Infura with your own API key.\"}]]]}]\n"])</script>
120<script>self.__next_f.push([1,"59:[\"$\",\"div\",null,{\"id\":\"contracts-explorer\",\"className\":\"scroll-mt-20 mt-8\",\"children\":[[\"$\",\"h3\",null,{\"className\":\"font-mono text-base font-semibold text-foreground mb-4\",\"children\":\"Explorer\"}],[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"View registered agents at\",\" \",[\"$\",\"a\",null,{\"href\":\"https://www.8004scan.io/\",\"target\":\"_blank\",\"rel\":\"noopener noreferrer\",\"className\":\"text-accent hover:text-blue-400 transition-colors duration-200 underline underline-offset-4 cursor-pointer\",\"children\":\"8004scan.io\"}]]}]]}]\n"])</script>
120<script>self.__next_f.push([1,"66:[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/next\"}],\" â exports: withSiwa, siwaOptions, corsJson\"]}]\n67:[\"$\",\"$L1a\",null,{\"title\":\"Next.js Example\",\"language\":\"typescript\",\"children\":\"// app/api/protected/route.ts\\nimport { withSiwa, siwaOptions } from \\\"@buildersgarden/siwa/next\\\";\\n\\nexport const POST = withSiwa(\\n async (agent, req) =\u003e {\\n // agent.address, agent.agentId, agent.chainId, agent.signerType\\n const body = await req.json();\\n return { received: body, agent };\\n },\\n {\\n // Optional: restrict to EOA-only agents\\n allowedSignerTypes: [\\\"eoa\\\"],\\n // Optional: re-verify onchain ownership on every request\\n verifyOnchain: true,\\n rpcUrl: process.env.RPC_URL,\\n }\\n);\\n\\nexport { siwaOptions as OPTIONS };\"}]\n68:[\"$\",\"div\",null,{\"id\":\"verify-wrappers-express\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Express\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/express\"}],\" â exports: siwaMiddleware, siwaJsonParser, siwaCors\"]}]]}]\n69:[\"$\",\"$L1a\",null,{\"title\":\"Express Example\",\"language\":\"typescript\",\"children\":\"import express from \\\"express\\\";\\nimport { siwaMiddleware, siwaJsonParser, siwaCors } from \\\"@buildersgarden/siwa/express\\\";\\nimport { createPublicClient, http } from \\\"viem\\\";\\nimport { baseSepolia } from \\\"viem/chains\\\";\\n\\nconst app = express();\\napp.use(siwaJsonParser());\\napp.use(siwaCors());\\n\\n// Optional: create a public client for ERC-1271 smart account support\\nconst publicClient = createPublicClient({\\n chain: baseSepolia,\\n transport: http(process.env.RPC_URL),\\n});\\n\\napp.post(\\n \\\"/api/protected\\\",\\n siwaMiddleware({\\n // Optional: allow both EOA and smart contract accounts\\n allowedSignerTypes: [\\\"eoa\\\", \\\"sca\\\"],\\n // Optional: pass publicClient for ERC-1271 signature verification\\n publicClient,\\n // Optional: re-verify onchain on every request\\n verifyOnchain: false,\\n }),\\n (req, res) =\u003e {\\n // req.agent contains { address, agentId, chainId, agentRegistry, signerType }\\n res.json({ agent: req.agent });\\n }\\n);\"}]\n6a:[\"$\",\"div\",null,{\"id\":\"verify-wrappers-hono\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Hono\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/hono\"}],\" â exports: siwaMiddleware, siwaCors\"]}]]}]\n85:T42e,import { Hono } from \"hono\";\nimport { siwaMiddleware, siwaCors } from \"@buildersgarden/siwa/hono\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst app = new Hono();\n\n// CORS with SIWA headers (handles preflight automatically)\napp.use(\"*\", siwaCors());\n\n// Optional: public client for ERC-1271 smart account support\nconst publicClient = createPublicClient({\n chain: baseSepolia,\n transport: http(process.env.RPC_URL),\n});\n\n// Route with EOA-only policy\napp.post(\n \"/api/eoa-only\",\n siwaMiddleware({ allowedSignerTypes: [\"eoa\"] }),\n (c) =\u003e c.json({ agent: c.get(\"agent\") }),\n);\n\n// Route allowing smart accounts with ERC-1271 verification\napp.post(\n \"/api/with-sca\",\n siwaMiddleware({ publicClient, allowedSignerTypes: [\"eoa\", \"sca\"] }),\n (c) =\u003e c.json({ agent: c.get(\"agent\") }),\n);\n\n// Route with onchain re-verification on every request\napp.post(\n \"/api/high-security\",\n siwaMiddleware({ verifyOnchain: true, rpcUrl: process.env.RPC_URL }),\n (c) =\u003e c.json({ agent: c.get(\"agent\") }),\n);\n\nexport default app;6b:[\"$\",\"$L1a\",null,{\"title\":\"Hono Example\",\"language\":\"typescript\",\"children\":\"$85\"}]\n6c:[\"$\",\"div"])</script>
120<script>self.__next_f.push([1,"\",null,{\"id\":\"verify-wrappers-fastify\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Fastify\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/fastify\"}],\" â exports: siwaPlugin, siwaAuth\"]}]]}]\n86:T453,import Fastify from \"fastify\";\nimport { siwaPlugin, siwaAuth } from \"@buildersgarden/siwa/fastify\";\nimport { createPublicClient, http } from \"viem\";\nimport { baseSepolia } from \"viem/chains\";\n\nconst fastify = Fastify();\n\n// Register CORS plugin with SIWA headers (handles preflight automatically)\nawait fastify.register(siwaPlugin);\n\n// Optional: public client for ERC-1271 smart account support\nconst publicClient = createPublicClient({\n chain: baseSepolia,\n transport: http(process.env.RPC_URL),\n});\n\n// Route with EOA-only policy\nfastify.post(\n \"/api/eoa-only\",\n { preHandler: siwaAuth({ allowedSignerTypes: [\"eoa\"] }) },\n async (req) =\u003e ({ agent: req.agent }),\n);\n\n// Route allowing smart accounts\nfastify.post(\n \"/api/with-sca\",\n { preHandler: siwaAuth({ publicClient, allowedSignerTypes: [\"eoa\", \"sca\"] }) },\n async (req) =\u003e ({ agent: req.agent }),\n);\n\n// Route with onchain re-verification\nfastify.post(\n \"/api/high-security\",\n { preHandler: siwaAuth({ verifyOnchain: true, rpcUrl: process.env.RPC_URL }) },\n async (req) =\u003e ({ agent: req.agent }),\n);\n\nawait fastify.listen({ port: 3000 });6d:[\"$\",\"$L1a\",null,{\"title\":\"Fastify Example\",\"language\":\"typescript\",\"children\":\"$86\"}]\n6e:[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Allow ±N tolerance on ASCII sum comparison.\"}]\n6f:[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"revealConstraints\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"true\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Include actual vs target values in verification results.\"}]]}]\n70:[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"consumeChallenge\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"â\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Callback for one-time-use tokens. Return false to reject replays.\"}]]}]\n71:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Override difficulty settings per tier with \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"captchaOptions.difficulties\"}],\":\"]}]\n72:[\"$\",\"$L19\",null,{\"language\":\"typescript\",\"children\":\"captchaOptions: {\\n secret: SIWA_SECRET,\\n verify: {\\n useServerTiming: true,\\n timingToleranceSeconds: 5,\\n revealConstraints: false,\\n consumeChallenge: (token) =\u003e redis.set(`captcha:${token}`, '1', 'NX', 'EX', 60).then(r =\u003e r === 'OK'),\\n },\\n difficulties: {\\n easy: { timeLimitSeconds: 45 },\\n extreme: { timeLimitSeconds: 8 },\\n },\\n}\"}]\n73:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/captcha\"}],\".\"]}]\n"])</script>
120<script>self.__next_f.push([1,"74:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Export\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Export\"}],[\"$\",\"th\",\"Side\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Side\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"solveCaptchaChallenge(nonceResponse, solver)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Detect + solve captcha from nonce response.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"retryWithCaptcha(response, request, ...)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Detect captcha in 401, solve, re-sign, return retry request. (from erc8128 module)\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"packCaptchaResponse(token, text)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Agent\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Package solution for submission.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"createCaptchaChallenge(difficulty, opts)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Generate challenge + HMAC-signed token.\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"verifyCaptchaSolution(token, solution, secret, verifyOpts?)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Verify all constraints + timing. Async.\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"unpackCaptchaResponse(packed)\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Server\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Unpack agent response.\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"75:[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"network\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"Chain identifier (e.g. \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"\\\"eip155:84532\\\"\"}],\").\"]}]]}]\n76:[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"amount\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Payment amount in smallest unit (e.g. wei, USDC base units).\"}]]}]\n77:[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"asset\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Token contract address.\"}]]}]\n78:[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"payTo\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Recipient address.\"}]]}]\n79:[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"maxTimeoutSeconds?\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"number\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Maximum time for settlement.\"}]]}]\n7a:[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"X402Payment (verified payment on request)\"}]}]\n"])</script>
120<script>self.__next_f.push([1,"7b:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Field\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Field\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"scheme\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Payment scheme.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"network\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Chain identifier.\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"amount\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Amount paid.\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"asset\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Token address.\"}]]}],[\"$\",\"tr\",\"4\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"payTo\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Recipient address.\"}]]}],[\"$\",\"tr\",\"5\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"txHash?\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"string\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"On-chain transaction hash from settlement.\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"7c:[\"$\",\"div\",null,{\"className\":\"mt-6 mb-3\",\"children\":[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"FacilitatorClient\"}]}]\n"])</script>
120<script>self.__next_f.push([1,"7d:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Method\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Method\"}],[\"$\",\"th\",\"Returns\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Returns\"}],[\"$\",\"th\",\"Description\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Description\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"verify(payload, requirements)\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"VerifyResponse\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Validate a payment signature.\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"settle(payload, requirements)\"}]}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"SettleResponse\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Execute on-chain settlement. Returns txHash on success.\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"7e:[\"$\",\"p\",null,{\"className\":\"text-sm leading-relaxed text-muted mb-4\",\"children\":[\"Use \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":[\"createFacilitatorClient(\",\"{ url }\",\")\"]}],\" to create a client that POSTs to \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/verify\"}],\" and \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"/settle\"}],\" endpoints on the facilitator. Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/x402\"}],\".\"]}]\n7f:[\"$\",\"div\",null,{\"id\":\"x402-hono\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Hono\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/hono\"}],\". Payment is available via \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"c.get(\\\"payment\\\")\"}],\".\"]}]]}]\n80:[\"$\",\"$L1a\",null,{\"title\":\"Hono x402 Example\",\"language\":\"typescript\",\"children\":\"import { Hono } from \\\"hono\\\";\\nimport { siwaMiddleware, siwaCors } from \\\"@buildersgarden/siwa/hono\\\";\\nimport { createFacilitatorClient } from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst app = new Hono();\\napp.use(\\\"*\\\", siwaCors({ x402: true }));\\n\\nconst facilitator = createFacilitatorClient({\\n url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\napp.post(\\n \\\"/api/premium\\\",\\n siwaMiddleware({\\n x402: {\\n facilitator,\\n resource: { url: \\\"/api/premium\\\", description: \\\"Premium endpoint\\\" },\\n accepts: [\\n {\\n scheme: \\\"exact\\\",\\n network: \\\"eip155:84532\\\",\\n amount: \\\"1000000\\\",\\n asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n payTo: \\\"0xYourAddress\\\",\\n },\\n ],\\n },\\n }),\\n (c) =\u003e {\\n const agent = c.get(\\\"agent\\\");\\n const payment = c.get(\\\"payment\\\");\\n return c.json({ agent, txHash: payment?.txHash });\\n },\\n);\"}]\n81:[\"$\",\"div\",null,{\"id\":\"x402-fastify\",\"className\":\"scroll-mt-20 mt-8 mb-2\",\"children\":[[\"$\",\"h4\",null,{\"className\":\"font-mono text-sm font-semibold text-foreground\",\"children\":\"Fastify\"}],[\"$\",\"p\",null,{\"className\":\"text-xs text-dim mb-3\",\"children\":[\"Import from \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"@buildersgarden/siwa/fastify\"}],\". Payment is available on \",[\"$\",\"code\",null,{\"className\":\"rounded bg-surface px-1.5 py-0.5 font-mono text-xs text-accent\",\"children\":\"req.payment\"}],\".\"]}]]}]\n82:[\"$\",\"$L1a\",null,{\"title\":\"Fastify x402 Example\",\"language\":\"typescript\",\"children\":\"import Fastify from \\\"fastify\\\";\\nimport { siwaPlugin, siwaAuth } from \\\"@buildersgarden/siwa/fastify\\\";\\nimport { createFacilitatorClient } from \\\"@buildersgarden/siwa/x402\\\";\\n\\nconst fastify = Fastify();\\nawait fastify.register(siwaPlugin, { x402: true });\\n\\nconst facilitator = createFacilitatorClient({\\n url: process.env.X402_FACILITATOR_URL!,\\n});\\n\\nfastify.post(\\n \\\"/api/premium\\\",\\n {\\n preHandler: siwaAuth({\\n x402: {\\n facilitator,\\n resource: { url: \\\"/api/premium\\\", description: \\\"Premium endpoint\\\" },\\n accepts: [\\n {\\n scheme: \\\"exact\\\",\\n network: \\\"eip155:84532\\\",\\n amount: \\\"1000000\\\",\\n asset: \\\"0x036CbD53842c5426634e7929541eC2318f3dCF7e\\\",\\n payTo: \\\"0xYourAddress\\\",\\n },\\n ],\\n },\\n }),\\n },\\n async (req) =\u003e {\\n // req.agent â verified SIWA identity\\n // req.payment â { scheme, network, amount, asset, payTo, txHash }\\n return { agent: req.agent, txHash: req.payment?.txHash };\\n },\\n);\"}]\n"])</script>
120<script>self.__next_f.push([1,"84:[\"$\",\"div\",null,{\"className\":\"overflow-x-auto mb-4\",\"children\":[\"$\",\"table\",null,{\"className\":\"w-full text-sm\",\"children\":[[\"$\",\"thead\",null,{\"children\":[\"$\",\"tr\",null,{\"className\":\"border-b border-border\",\"children\":[[\"$\",\"th\",\"Network\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Network\"}],[\"$\",\"th\",\"Chain ID\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Chain ID\"}],[\"$\",\"th\",\"Type\",{\"className\":\"py-2 pr-4 text-left font-mono text-xs font-medium text-dim\",\"children\":\"Type\"}]]}]}],[\"$\",\"tbody\",null,{\"children\":[[\"$\",\"tr\",\"0\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"1\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Mainnet\"}]]}],[\"$\",\"tr\",\"1\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"8453\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Mainnet\"}]]}],[\"$\",\"tr\",\"2\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Base Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"84532\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Testnet\"}]]}],[\"$\",\"tr\",\"3\",{\"className\":\"border-b border-border/50\",\"children\":[[\"$\",\"td\",\"0\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Ethereum Sepolia\"}],[\"$\",\"td\",\"1\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"11155111\"}],[\"$\",\"td\",\"2\",{\"className\":\"py-2 pr-4 text-muted font-mono text-xs\",\"children\":\"Testnet\"}]]}]]}]]}]}]\n"])</script>
120<script>self.__next_f.push([1,"5e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script>
120<script>self.__next_f.push([1,"87:I[20414,[\"/_next/static/chunks/33074d3ff5d0cd2d.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\",\"/_next/static/chunks/4141b86737d3d211.js?dpl=dpl_5UBMJ54WbXgny1f7PytuERL3ViB7\"],\"IconMark\"]\n5c:null\n60:[[\"$\",\"title\",\"0\",{\"children\":\"Docs â SIWA\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Documentation for SIWA (Sign In With Agent) â getting started, API reference, wallet integration, and contract addresses.\"}],[\"$\",\"meta\",\"2\",{\"property\":\"og:title\",\"content\":\"SIWA â Sign In With Agent\"}],[\"$\",\"meta\",\"3\",{\"property\":\"og:description\",\"content\":\"Trustless identity and authentication for AI agents. An open standard built on ERC-8004 and ERC-8128.\"}],[\"$\",\"meta\",\"4\",{\"property\":\"og:image\",\"content\":\"https://siwa.id/og.png\"}],[\"$\",\"meta\",\"5\",{\"property\":\"og:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"6\",{\"property\":\"og:image:height\",\"content\":\"630\"}],[\"$\",\"meta\",\"7\",{\"property\":\"og:image:alt\",\"content\":\"SIWA â Sign In With Agent\"}],[\"$\",\"meta\",\"8\",{\"property\":\"og:type\",\"content\":\"website\"}],[\"$\",\"meta\",\"9\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],[\"$\",\"meta\",\"10\",{\"name\":\"twitter:title\",\"content\":\"SIWA â Sign In With Agent\"}],[\"$\",\"meta\",\"11\",{\"name\":\"twitter:description\",\"content\":\"Trustless identity and authentication for AI agents. An open standard built on ERC-8004 and ERC-8128.\"}],[\"$\",\"meta\",\"12\",{\"name\":\"twitter:image\",\"content\":\"https://siwa.id/og.png\"}],[\"$\",\"link\",\"13\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.4c82eb06.ico\",\"sizes\":\"32x32\",\"type\":\"image/x-icon\"}],[\"$\",\"$L87\",\"14\",{}]]\n"])</script>
120</body></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.