1
0

agents.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import { supabase } from "@/utils/supabase";
  2. import { ethers } from "ethers";
  3. import { AgentTier, calculatePrice, calculateTier } from "@/utils/agentUtils";
  4. import type { Agent } from "@/types/agent";
  5. import {
  6. getEthcallProvider,
  7. getMainContract,
  8. getMainEthcallContract,
  9. getProvider,
  10. } from "@/lib/provider";
  11. import { decodeAgentId } from "@/utils/fileUtils";
  12. export async function getAgentsFromSupabase(agentId?: string | null) {
  13. const agentFields = [
  14. "id",
  15. "agentId",
  16. "name",
  17. "token",
  18. "description",
  19. "status",
  20. "avatar",
  21. "category",
  22. "tags",
  23. "vrmUrl",
  24. "bgUrl",
  25. "config",
  26. "integrations",
  27. "systemPrompt",
  28. "visionSystemPrompt",
  29. ].join(",");
  30. let query = supabase
  31. .from("agents")
  32. .select(agentFields)
  33. .neq("blackList", true);
  34. if (agentId) {
  35. query = query.eq("agentId", agentId);
  36. }
  37. const { data, error } = await query;
  38. if (error) throw error;
  39. return data;
  40. }
  41. // Fetch and enrich agents with price and tier info
  42. export async function fetchAgentStats(
  43. agents: Agent | Agent[],
  44. ): Promise<Agent | Agent[]> {
  45. const agentArray = Array.isArray(agents) ? agents : [agents];
  46. const provider = getProvider();
  47. const contract = getMainContract();
  48. const pairContractCache = new Map<string, ethers.Contract>();
  49. const token0Cache = new Map<string, string>();
  50. const updatedAgents: Agent[] = [];
  51. for (const agent of agentArray) {
  52. const tokenId = Number(agent.id);
  53. let price = 0;
  54. let stakedAius = 0;
  55. let erc20: `0x${string}` = '0x';
  56. let tier: AgentTier = { name: "None", level: 0, stakedAIUS: 0 };
  57. try {
  58. // Get erc20 ca
  59. const tokenURI = await contract.tokenURI(tokenId);
  60. const base64 = tokenURI.replace(/^data:application\/json;base64,/, "");
  61. const jsonStr = Buffer.from(base64, "base64").toString("utf-8");
  62. const metadata = JSON.parse(jsonStr);
  63. const erc20Attr = metadata.attributes?.find(
  64. (attr: any) => attr.trait_type === "ERC20 Address"
  65. );
  66. erc20 = erc20Attr.value;
  67. const tokenData = await contract.getTokenData(tokenId);
  68. [stakedAius, price] = await calculatePrice(
  69. contract,
  70. provider,
  71. pairContractCache,
  72. token0Cache,
  73. tokenData,
  74. );
  75. tier = await calculateTier(
  76. contract,
  77. tokenId,
  78. price,
  79. stakedAius,
  80. tokenData,
  81. );
  82. } catch (err) {
  83. const reason = (err as any)?.revert?.args?.[0] ?? (err as any)?.reason;
  84. if (reason === "Pair not created") {
  85. console.warn(`Token ${tokenId}: Pair not created`);
  86. } else {
  87. console.warn(
  88. `Failed to calculate price/tier for token ${tokenId}`,
  89. err,
  90. );
  91. }
  92. }
  93. updatedAgents.push({ ...agent, price, tier, erc20 });
  94. }
  95. // Return a single Agent if the input was a single Agent
  96. return Array.isArray(agents) ? updatedAgents : updatedAgents[0];
  97. }
  98. export const METADATA_KEYS = [
  99. "agent_id",
  100. "name",
  101. "description",
  102. "image",
  103. "vrm_url",
  104. "bg_url",
  105. "tags",
  106. "agent_category",
  107. "chatbot_backend",
  108. "tts_backend",
  109. "stt_backend",
  110. "vision_backend",
  111. "brain",
  112. "virtuals",
  113. "eacc",
  114. "uos",
  115. "system_prompt",
  116. "vision_system_prompt",
  117. ];
  118. export async function getAgentFromContract(
  119. agentId: string,
  120. ): Promise<Agent | null> {
  121. const ethcallContract = getMainEthcallContract();
  122. const ethcallProvider = await getEthcallProvider();
  123. const tokenId = decodeAgentId(agentId);
  124. const [metadata] = await ethcallProvider.all([
  125. ethcallContract.getMetadata(tokenId, METADATA_KEYS),
  126. ]);
  127. if (
  128. !Array.isArray(metadata) ||
  129. metadata.length === 0 ||
  130. metadata[0] === "0x"
  131. ) {
  132. console.warn(`No metadata found for tokenId: ${tokenId}`);
  133. return null;
  134. }
  135. const [
  136. agentid,
  137. name,
  138. description,
  139. image,
  140. vrmUrl,
  141. bgUrl,
  142. tags,
  143. agentCategory,
  144. chatbot,
  145. tts,
  146. stt,
  147. vision,
  148. brain,
  149. virtuals,
  150. eacc,
  151. uos,
  152. systemPrompt,
  153. visionSystemPrompt,
  154. ] = metadata;
  155. const integrations: Record<string, string> = {};
  156. if (brain) integrations.brain = brain;
  157. if (virtuals) integrations.virtuals = virtuals;
  158. if (eacc) integrations.eacc = eacc;
  159. if (uos) integrations.uos = uos;
  160. const agent: Agent = {
  161. id: `${tokenId}`,
  162. agentId: agentid,
  163. name: name || "Unknown",
  164. token: "AINFT",
  165. description: description || "No description available",
  166. price: 0,
  167. status: "status",
  168. avatar: image,
  169. category: agentCategory || "All Agents",
  170. tags: tags?.split(",") || [],
  171. tier: { name: "None", level: 0, stakedAIUS: 0 },
  172. vrmUrl,
  173. bgUrl,
  174. config: {
  175. chatbot,
  176. tts,
  177. stt,
  178. vision,
  179. amicaLife: "amicaLife",
  180. rvc: "rvc",
  181. },
  182. integrations,
  183. systemPrompt,
  184. visionSystemPrompt,
  185. };
  186. return agent;
  187. }
  188. type SupportedNetworks =
  189. | "mainnet"
  190. | "sepolia"
  191. | "arbitrum"
  192. | "arbitrumSepolia";
  193. export function getExplorerUrl(address: `0x${string}`, network: SupportedNetworks = "sepolia"): string {
  194. const explorerBaseMap: Record<SupportedNetworks, string> = {
  195. mainnet: "https://etherscan.io",
  196. sepolia: "https://sepolia.etherscan.io",
  197. arbitrum: "https://arbiscan.io",
  198. arbitrumSepolia: "https://sepolia.arbiscan.io",
  199. };
  200. const base = explorerBaseMap[network];
  201. return `${base}/address/${address}`;
  202. }