import { supabase } from "@/utils/supabase"; import { ethers } from "ethers"; import { AgentTier, calculatePrice, calculateTier } from "@/utils/agentUtils"; import type { Agent } from "@/types/agent"; import { getEthcallProvider, getMainContract, getMainEthcallContract, getProvider, } from "@/lib/provider"; import { decodeAgentId } from "@/utils/fileUtils"; export async function getAgentsFromSupabase(agentId?: string | null) { const agentFields = [ "id", "agentId", "name", "token", "description", "status", "avatar", "category", "tags", "vrmUrl", "bgUrl", "config", "integrations", "systemPrompt", "visionSystemPrompt", ].join(","); let query = supabase .from("agents") .select(agentFields) .neq("blackList", true); if (agentId) { query = query.eq("agentId", agentId); } const { data, error } = await query; if (error) throw error; return data; } // Fetch and enrich agents with price and tier info export async function fetchAgentStats( agents: Agent | Agent[], ): Promise { const agentArray = Array.isArray(agents) ? agents : [agents]; const provider = getProvider(); const contract = getMainContract(); const pairContractCache = new Map(); const token0Cache = new Map(); const updatedAgents: Agent[] = []; for (const agent of agentArray) { const tokenId = Number(agent.id); let price = 0; let stakedAius = 0; let erc20: `0x${string}` = '0x'; let tier: AgentTier = { name: "None", level: 0, stakedAIUS: 0 }; try { // Get erc20 ca const tokenURI = await contract.tokenURI(tokenId); const base64 = tokenURI.replace(/^data:application\/json;base64,/, ""); const jsonStr = Buffer.from(base64, "base64").toString("utf-8"); const metadata = JSON.parse(jsonStr); const erc20Attr = metadata.attributes?.find( (attr: any) => attr.trait_type === "ERC20 Address" ); erc20 = erc20Attr.value; const tokenData = await contract.getTokenData(tokenId); [stakedAius, price] = await calculatePrice( contract, provider, pairContractCache, token0Cache, tokenData, ); tier = await calculateTier( contract, tokenId, price, stakedAius, tokenData, ); } catch (err) { const reason = (err as any)?.revert?.args?.[0] ?? (err as any)?.reason; if (reason === "Pair not created") { console.warn(`Token ${tokenId}: Pair not created`); } else { console.warn( `Failed to calculate price/tier for token ${tokenId}`, err, ); } } updatedAgents.push({ ...agent, price, tier, erc20 }); } // Return a single Agent if the input was a single Agent return Array.isArray(agents) ? updatedAgents : updatedAgents[0]; } export const METADATA_KEYS = [ "agent_id", "name", "description", "image", "vrm_url", "bg_url", "tags", "agent_category", "chatbot_backend", "tts_backend", "stt_backend", "vision_backend", "brain", "virtuals", "eacc", "uos", "system_prompt", "vision_system_prompt", ]; export async function getAgentFromContract( agentId: string, ): Promise { const ethcallContract = getMainEthcallContract(); const ethcallProvider = await getEthcallProvider(); const tokenId = decodeAgentId(agentId); const [metadata] = await ethcallProvider.all([ ethcallContract.getMetadata(tokenId, METADATA_KEYS), ]); if ( !Array.isArray(metadata) || metadata.length === 0 || metadata[0] === "0x" ) { console.warn(`No metadata found for tokenId: ${tokenId}`); return null; } const [ agentid, name, description, image, vrmUrl, bgUrl, tags, agentCategory, chatbot, tts, stt, vision, brain, virtuals, eacc, uos, systemPrompt, visionSystemPrompt, ] = metadata; const integrations: Record = {}; if (brain) integrations.brain = brain; if (virtuals) integrations.virtuals = virtuals; if (eacc) integrations.eacc = eacc; if (uos) integrations.uos = uos; const agent: Agent = { id: `${tokenId}`, agentId: agentid, name: name || "Unknown", token: "AINFT", description: description || "No description available", price: 0, status: "status", avatar: image, category: agentCategory || "All Agents", tags: tags?.split(",") || [], tier: { name: "None", level: 0, stakedAIUS: 0 }, vrmUrl, bgUrl, config: { chatbot, tts, stt, vision, amicaLife: "amicaLife", rvc: "rvc", }, integrations, systemPrompt, visionSystemPrompt, }; return agent; } type SupportedNetworks = | "mainnet" | "sepolia" | "arbitrum" | "arbitrumSepolia"; export function getExplorerUrl(address: `0x${string}`, network: SupportedNetworks = "sepolia"): string { const explorerBaseMap: Record = { mainnet: "https://etherscan.io", sepolia: "https://sepolia.etherscan.io", arbitrum: "https://arbiscan.io", arbitrumSepolia: "https://sepolia.arbiscan.io", }; const base = explorerBaseMap[network]; return `${base}/address/${address}`; }