From 115eb9c263ca2a421fd9a462616b2b01d1812bc8 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Fri, 24 Apr 2026 12:19:56 +0900 Subject: [PATCH] [#154] Cache agent ID locally to survive RPC rate limits Public RPC (mainnet.base.org) intermittently fails, causing the Settings page to show the registration form even when the wallet is already registered. Now caches agent_id in local SQLite after first successful RPC detection. Subsequent page loads read from cache without RPC calls. Co-Authored-By: Claude Opus 4.6 (1M context) --- app/routes/settings.ts | 33 ++++++++++++++++++--------------- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/app/routes/settings.ts b/app/routes/settings.ts index 14a1bed..d386070 100644 --- a/app/routes/settings.ts +++ b/app/routes/settings.ts @@ -161,6 +161,13 @@ settings.get("/link-status", async (c) => { const address = getBaseAddress(wallet); if (!address) return c.json({ linked: false, error: "No EVM address" }); + // Check local cache first (survives RPC rate limits) + const cached = await db.setting.findUnique({ where: { key: "agent_id" } }); + if (cached) { + return c.json({ linked: true, agentId: Number(cached.value), owsWallet: address }); + } + + // RPC: try agentIdByWallet (for bound wallets) try { const agentId = await publicClient.readContract({ address: ERC_8004, @@ -170,21 +177,13 @@ settings.get("/link-status", async (c) => { }) as bigint; if (agentId > 0n) { - // Fetch NFT owner (ERC-721 ownerOf) - let owner: string | undefined; - try { - owner = await publicClient.readContract({ - address: ERC_8004, - abi: [{ type: "function", name: "ownerOf", stateMutability: "view", inputs: [{ name: "tokenId", type: "uint256" }], outputs: [{ name: "", type: "address" }] }] as const, - functionName: "ownerOf", - args: [agentId], - }) as string; - } catch { /* best effort */ } - return c.json({ linked: true, agentId: Number(agentId), owsWallet: address, owner }); + // Cache locally + await db.setting.upsert({ where: { key: "agent_id" }, update: { value: String(agentId) }, create: { key: "agent_id", value: String(agentId) } }); + return c.json({ linked: true, agentId: Number(agentId), owsWallet: address }); } } catch { /* agentIdByWallet may revert if not bound */ } - // Fallback: check if wallet owns an agent NFT (register() creates NFT but doesn't bind via setAgentWallet) + // RPC fallback: check balanceOf (for owned but unbound NFTs) try { const balance = await publicClient.readContract({ address: ERC_8004, @@ -194,7 +193,7 @@ settings.get("/link-status", async (c) => { }) as bigint; if (balance > 0n) { - // Try to get token ID (ERC-721 Enumerable — may not be supported) + // Try to get token ID let agentId: number | undefined; try { const tokenId = await publicClient.readContract({ @@ -204,11 +203,15 @@ settings.get("/link-status", async (c) => { args: [address as `0x${string}`, 0n], }) as bigint; agentId = Number(tokenId); - } catch { /* ERC-721 Enumerable not supported — agent ID unknown */ } + } catch { /* ERC-721 Enumerable not supported */ } + // Cache if we got the ID + if (agentId !== undefined) { + await db.setting.upsert({ where: { key: "agent_id" }, update: { value: String(agentId) }, create: { key: "agent_id", value: String(agentId) } }); + } return c.json({ linked: true, agentId, owsWallet: address }); } - } catch { /* balanceOf failed */ } + } catch { /* RPC failed — rate limited or unavailable */ } return c.json({ linked: false, owsWallet: address }); } catch (err: unknown) { diff --git a/package-lock.json b/package-lock.json index 2970536..fd9edcf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "plotlink-ows", - "version": "1.0.16", + "version": "1.0.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "plotlink-ows", - "version": "1.0.16", + "version": "1.0.17", "hasInstallScript": true, "workspaces": [ "packages/*" diff --git a/package.json b/package.json index bf8b425..40df95a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plotlink-ows", - "version": "1.0.16", + "version": "1.0.17", "bin": { "plotlink-ows": "./bin/plotlink-ows.js" },