diff --git a/lib/actions.ts b/lib/actions.ts index dec1acbb..8d5a3829 100644 --- a/lib/actions.ts +++ b/lib/actions.ts @@ -1,6 +1,11 @@ "use server"; import { lookupByAddress, type FarcasterProfile } from "./farcaster"; +import { + getAgentMetadata as _getAgentMetadata, + type AgentMetadata, +} from "./contracts/erc8004"; +import type { Address } from "viem"; /** * Server action that resolves an Ethereum address to a Farcaster profile. @@ -11,3 +16,12 @@ export async function getFarcasterProfile( ): Promise { return lookupByAddress(address); } + +/** + * Server action that resolves ERC-8004 agent metadata from a wallet address. + */ +export async function fetchAgentMetadata( + address: string, +): Promise { + return _getAgentMetadata(address as Address); +} diff --git a/lib/contracts/erc8004.ts b/lib/contracts/erc8004.ts index 0179c941..ef028e2c 100644 --- a/lib/contracts/erc8004.ts +++ b/lib/contracts/erc8004.ts @@ -10,6 +10,15 @@ import { ERC8004_REGISTRY } from "./constants"; * ERC-8004 Agent Registry ABI — agent registration, wallet binding, and * reverse lookup. */ +export interface AgentMetadata { + name: string; + description: string; + genre?: string; + llmModel?: string; + registeredBy?: string; + registeredAt?: string; +} + export const erc8004Abi = [ // View { @@ -19,6 +28,13 @@ export const erc8004Abi = [ inputs: [{ name: "wallet", type: "address" }], outputs: [{ name: "agentId", type: "uint256" }], }, + { + type: "function", + name: "agentURI", + stateMutability: "view", + inputs: [{ name: "agentId", type: "uint256" }], + outputs: [{ name: "", type: "string" }], + }, // Write — register a new agent { type: "function", @@ -77,3 +93,41 @@ export async function detectWriterType( return 0; } } + +/** + * Resolve ERC-8004 agent metadata from an Ethereum address. + * Returns null if the address is not a registered agent or on any error. + */ +export async function getAgentMetadata( + walletAddress: Address, +): Promise { + try { + const agentId = await publicClient.readContract({ + address: ERC8004_REGISTRY, + abi: erc8004Abi, + functionName: "agentIdByWallet", + args: [walletAddress], + }); + if (agentId <= BigInt(0)) return null; + + const uri = await publicClient.readContract({ + address: ERC8004_REGISTRY, + abi: erc8004Abi, + functionName: "agentURI", + args: [agentId], + }); + if (!uri) return null; + + const parsed = JSON.parse(uri as string) as Record; + return { + name: (parsed.name as string) || "Unknown Agent", + description: (parsed.description as string) || "", + genre: (parsed.genre as string) || undefined, + llmModel: (parsed.llmModel as string) || (parsed.model as string) || undefined, + registeredBy: (parsed.registeredBy as string) || undefined, + registeredAt: (parsed.registeredAt as string) || undefined, + }; + } catch { + return null; + } +} diff --git a/lib/farcaster.ts b/lib/farcaster.ts index d0aaa091..ee79ea39 100644 --- a/lib/farcaster.ts +++ b/lib/farcaster.ts @@ -12,6 +12,7 @@ export interface FarcasterProfile { username: string; displayName: string; pfpUrl: string | null; + bio: string | null; } const STEEMHUNT_BASE = "https://fc.hunt.town"; @@ -40,6 +41,7 @@ async function steemhuntLookup(address: string): Promise { username: data.username, displayName: data.displayName ?? data.username, pfpUrl: data.pfpUrl ?? null, + bio: data.bio ?? data.profile?.bio?.text ?? null, }; } @@ -63,6 +65,7 @@ async function neynarLookup(address: string): Promise { username: user.username, displayName: user.display_name ?? user.username, pfpUrl: user.pfp_url ?? null, + bio: user.profile?.bio?.text ?? null, }; } diff --git a/src/app/dashboard/writer/page.tsx b/src/app/dashboard/writer/page.tsx index cb4c7813..cffb5348 100644 --- a/src/app/dashboard/writer/page.tsx +++ b/src/app/dashboard/writer/page.tsx @@ -233,9 +233,12 @@ function WriterDonationHistory({ storylineId }: { storylineId: number }) { className="text-muted flex items-center justify-between text-[10px]" >
- + {truncateAddress(d.donor_address)} - + {d.block_timestamp && (