UNPKG

@elizaos/plugin-squid-router

Version:

ElizaOS plugin for cross-chain token swaps using Squid Router

159 lines (142 loc) 4.79 kB
import type { IAgentRuntime } from "@elizaos/core"; import { z } from "zod"; import { ethers } from "ethers"; import type { SquidToken, XChainSwapContent } from "../types"; export function convertToWei( amount: string | number, token: SquidToken ): string { if ( typeof token.decimals !== "number" || token.decimals < 0 || token.decimals > 255 ) { throw new Error("Invalid decimals value in token object."); } try { // Ensure amount is a string for ethers.js const amountString = typeof amount === "number" ? amount.toString() : amount; // Use ethers.js to parse the amount into the smallest unit const parsedAmount = ethers.parseUnits(amountString, token.decimals); // Return the parsed amount as a string return parsedAmount.toString(); } catch (error) { throw new Error(`Failed to convert amount: ${(error as Error).message}`); } } export function isXChainSwapContent(content: XChainSwapContent): boolean { // Validate types const validTypes = typeof content.fromChain === "string" && typeof content.toChain === "string" && typeof content.fromToken === "string" && typeof content.toToken === "string" && typeof content.toAddress === "string" && (typeof content.amount === "string" || typeof content.amount === "number"); if (validTypes) { return true; } return false; } // Helper Validation Functions const isValidEvmAddress = (address: string): boolean => { return ethers.isAddress(address); }; const isValidEvmPrivateKey = (key: string): boolean => { const cleanedKey = key.startsWith("0x") ? key.slice(2) : key; return /^[0-9a-fA-F]{64}$/.test(cleanedKey); }; export const squidRouterEnvSchema = z .object({ SQUID_INTEGRATOR_ID: z.string().min(1, "Squid Integrator ID is required"), SQUID_SDK_URL: z.string().min(1, "Squid SDK URL is required"), SQUID_EVM_ADDRESS: z.string().min(1, "Squid Integrator ID is required"), SQUID_EVM_PRIVATE_KEY: z.string().min(1, "Squid Integrator ID is required"), }) .refine( (data) => { // Check if EVM pair is valid const evmValid = data.SQUID_EVM_ADDRESS && data.SQUID_EVM_PRIVATE_KEY && isValidEvmAddress(data.SQUID_EVM_ADDRESS) && isValidEvmPrivateKey(data.SQUID_EVM_PRIVATE_KEY); return evmValid; }, { message: "At least one valid address and private key pair is required: EVM, Solana, or Cosmos.", path: [], // Global error } ) .superRefine((data, ctx) => { // EVM Validation if (data.SQUID_EVM_ADDRESS || data.SQUID_EVM_PRIVATE_KEY) { if ( data.SQUID_EVM_ADDRESS && !isValidEvmAddress(data.SQUID_EVM_ADDRESS) ) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "EVM_ADDRESS is invalid or not checksummed correctly.", path: ["EVM_ADDRESS"], }); } if ( data.SQUID_EVM_PRIVATE_KEY && !isValidEvmPrivateKey(data.SQUID_EVM_PRIVATE_KEY) ) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "EVM_PRIVATE_KEY must be a 64-character hexadecimal string.", path: ["EVM_PRIVATE_KEY"], }); } if ( (data.SQUID_EVM_ADDRESS && !data.SQUID_EVM_PRIVATE_KEY) || (!data.SQUID_EVM_ADDRESS && data.SQUID_EVM_PRIVATE_KEY) ) { if (!data.SQUID_EVM_ADDRESS) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "EVM_ADDRESS is required when EVM_PRIVATE_KEY is provided.", path: ["EVM_ADDRESS"], }); } if (!data.SQUID_EVM_PRIVATE_KEY) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "EVM_PRIVATE_KEY is required when EVM_ADDRESS is provided.", path: ["EVM_PRIVATE_KEY"], }); } } } }); export type SquidRouterConfig = z.infer<typeof squidRouterEnvSchema>; export async function validateSquidRouterConfig( runtime: IAgentRuntime ): Promise<SquidRouterConfig> { try { const config = { SQUID_INTEGRATOR_ID: runtime.getSetting("SQUID_INTEGRATOR_ID"), SQUID_SDK_URL: runtime.getSetting("SQUID_SDK_URL"), SQUID_EVM_ADDRESS: runtime.getSetting("SQUID_EVM_ADDRESS"), SQUID_EVM_PRIVATE_KEY: runtime.getSetting("SQUID_EVM_PRIVATE_KEY"), }; return squidRouterEnvSchema.parse(config); } catch (error) { if (error instanceof z.ZodError) { const errorMessages = error.errors .map((err) => `${err.path.join(".")}: ${err.message}`) .join("\n"); throw new Error( `Squid Router configuration validation failed:\n${errorMessages}` ); } throw error; } }