UNPKG

@elizaos/plugin-squid-router

Version:

ElizaOS plugin for cross-chain token swaps using Squid Router

435 lines (373 loc) 12.4 kB
import { describe, it, expect, beforeEach, mock } from "bun:test"; import { convertToWei, isXChainSwapContent, validateSquidRouterConfig, squidRouterEnvSchema, } from "../helpers/utils"; import { createMockRuntime } from "./test-utils"; import { z } from "zod"; describe("convertToWei", () => { it("should convert whole numbers correctly", () => { const token = { decimals: 18, isNative: true, symbol: "ETH", address: "0x", enabled: true, }; const result = convertToWei("1", token); expect(result).toBe("1000000000000000000"); }); it("should convert decimal numbers correctly", () => { const token = { decimals: 6, isNative: false, symbol: "USDC", address: "0x", enabled: true, }; const result = convertToWei("100.5", token); expect(result).toBe("100500000"); }); it("should handle numbers as input", () => { const token = { decimals: 18, isNative: true, symbol: "ETH", address: "0x", enabled: true, }; const result = convertToWei(0.5, token); expect(result).toBe("500000000000000000"); }); it("should handle zero decimals", () => { const token = { decimals: 0, isNative: false, symbol: "TEST", address: "0x", enabled: true, }; const result = convertToWei("100", token); expect(result).toBe("100"); }); it("should throw error for invalid decimals", () => { const token = { decimals: -1, isNative: false, symbol: "TEST", address: "0x", enabled: true, }; expect(() => convertToWei("100", token)).toThrow("Invalid decimals value"); }); it("should throw error for decimals > 255", () => { const token = { decimals: 256, isNative: false, symbol: "TEST", address: "0x", enabled: true, }; expect(() => convertToWei("100", token)).toThrow("Invalid decimals value"); }); it("should throw error for invalid amount", () => { const token = { decimals: 18, isNative: false, symbol: "TEST", address: "0x", enabled: true, }; expect(() => convertToWei("invalid", token)).toThrow( "Failed to convert amount" ); }); it("should handle very small amounts", () => { const token = { decimals: 18, isNative: true, symbol: "ETH", address: "0x", enabled: true, }; const result = convertToWei("0.000000000000000001", token); expect(result).toBe("1"); }); it("should handle very large amounts", () => { const token = { decimals: 18, isNative: true, symbol: "ETH", address: "0x", enabled: true, }; const result = convertToWei("1000000", token); expect(result).toBe("1000000000000000000000000"); }); }); describe("isXChainSwapContent", () => { it("should return true for valid content", () => { const content = { fromChain: "ethereum", toChain: "base", fromToken: "ETH", toToken: "ETH", amount: "1", toAddress: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", }; expect(isXChainSwapContent(content as any)).toBe(true); }); it("should accept number amount", () => { const content = { fromChain: "ethereum", toChain: "base", fromToken: "ETH", toToken: "ETH", amount: 1, toAddress: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", }; expect(isXChainSwapContent(content as any)).toBe(true); }); it("should return false for missing fromChain", () => { const content = { toChain: "base", fromToken: "ETH", toToken: "ETH", amount: "1", toAddress: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", }; expect(isXChainSwapContent(content as any)).toBe(false); }); it("should return false for missing toChain", () => { const content = { fromChain: "ethereum", fromToken: "ETH", toToken: "ETH", amount: "1", toAddress: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", }; expect(isXChainSwapContent(content as any)).toBe(false); }); it("should return false for missing fromToken", () => { const content = { fromChain: "ethereum", toChain: "base", toToken: "ETH", amount: "1", toAddress: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", }; expect(isXChainSwapContent(content as any)).toBe(false); }); it("should return false for missing toToken", () => { const content = { fromChain: "ethereum", toChain: "base", fromToken: "ETH", amount: "1", toAddress: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", }; expect(isXChainSwapContent(content as any)).toBe(false); }); it("should return false for missing amount", () => { const content = { fromChain: "ethereum", toChain: "base", fromToken: "ETH", toToken: "ETH", toAddress: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", }; expect(isXChainSwapContent(content as any)).toBe(false); }); it("should return false for missing toAddress", () => { const content = { fromChain: "ethereum", toChain: "base", fromToken: "ETH", toToken: "ETH", amount: "1", }; expect(isXChainSwapContent(content as any)).toBe(false); }); it("should return false for wrong type fields", () => { const content = { fromChain: 123, toChain: "base", fromToken: "ETH", toToken: "ETH", amount: "1", toAddress: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", }; expect(isXChainSwapContent(content as any)).toBe(false); }); it("should return false for null values", () => { const content = { fromChain: null, toChain: "base", fromToken: "ETH", toToken: "ETH", amount: "1", toAddress: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", }; expect(isXChainSwapContent(content as any)).toBe(false); }); }); describe("validateSquidRouterConfig", () => { let mockRuntime: any; beforeEach(() => { mockRuntime = createMockRuntime(); }); it("should validate valid configuration", async () => { const config = await validateSquidRouterConfig(mockRuntime); expect(config).toBeDefined(); expect(config.SQUID_INTEGRATOR_ID).toBe("test-integrator-id"); expect(config.SQUID_SDK_URL).toBe("https://apiplus.squidrouter.com"); expect(config.SQUID_EVM_ADDRESS).toBe( "0x742D35Cc6634c0532925A3b844BC9E7595f6F269" ); expect(config.SQUID_EVM_PRIVATE_KEY).toBe( "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" ); }); it("should throw error for missing integrator ID", async () => { mockRuntime.getSetting.mockImplementation((key: string) => { if (key === "SQUID_INTEGRATOR_ID") return undefined; return createMockRuntime().getSetting(key); }); await expect(validateSquidRouterConfig(mockRuntime)).rejects.toThrow( "Required" ); }); it("should throw error for missing SDK URL", async () => { mockRuntime.getSetting.mockImplementation((key: string) => { if (key === "SQUID_SDK_URL") return undefined; return createMockRuntime().getSetting(key); }); await expect(validateSquidRouterConfig(mockRuntime)).rejects.toThrow( "Required" ); }); it("should throw error for invalid EVM address", async () => { mockRuntime.getSetting.mockImplementation((key: string) => { if (key === "SQUID_EVM_ADDRESS") return "invalid-address"; return createMockRuntime().getSetting(key); }); await expect(validateSquidRouterConfig(mockRuntime)).rejects.toThrow( "EVM_ADDRESS is invalid" ); }); it("should throw error for invalid EVM private key", async () => { mockRuntime.getSetting.mockImplementation((key: string) => { if (key === "SQUID_EVM_PRIVATE_KEY") return "invalid-key"; return createMockRuntime().getSetting(key); }); await expect(validateSquidRouterConfig(mockRuntime)).rejects.toThrow( "64-character hexadecimal string" ); }); it("should accept private key with 0x prefix", async () => { mockRuntime.getSetting.mockImplementation((key: string) => { if (key === "SQUID_EVM_PRIVATE_KEY") { return "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; } return createMockRuntime().getSetting(key); }); const config = await validateSquidRouterConfig(mockRuntime); expect(config.SQUID_EVM_PRIVATE_KEY).toBeDefined(); }); it("should accept private key without 0x prefix", async () => { mockRuntime.getSetting.mockImplementation((key: string) => { if (key === "SQUID_EVM_PRIVATE_KEY") { return "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; } return createMockRuntime().getSetting(key); }); const config = await validateSquidRouterConfig(mockRuntime); expect(config.SQUID_EVM_PRIVATE_KEY).toBeDefined(); }); it("should throw error when EVM address is provided without private key", async () => { mockRuntime.getSetting.mockImplementation((key: string) => { if (key === "SQUID_EVM_PRIVATE_KEY") return undefined; return createMockRuntime().getSetting(key); }); await expect(validateSquidRouterConfig(mockRuntime)).rejects.toThrow( "SQUID_EVM_PRIVATE_KEY: Required" ); }); it("should throw error when EVM private key is provided without address", async () => { mockRuntime.getSetting.mockImplementation((key: string) => { if (key === "SQUID_EVM_ADDRESS") return undefined; return createMockRuntime().getSetting(key); }); await expect(validateSquidRouterConfig(mockRuntime)).rejects.toThrow( "SQUID_EVM_ADDRESS: Required" ); }); it("should handle non-Zod errors", async () => { mockRuntime.getSetting.mockImplementation(() => { throw new Error("Unexpected error"); }); await expect(validateSquidRouterConfig(mockRuntime)).rejects.toThrow( "Unexpected error" ); }); }); describe("squidRouterEnvSchema", () => { it("should accept valid configuration", () => { const config = { SQUID_INTEGRATOR_ID: "test-id", SQUID_SDK_URL: "https://api.squid.com", SQUID_EVM_ADDRESS: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", SQUID_EVM_PRIVATE_KEY: "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", }; const result = squidRouterEnvSchema.parse(config); expect(result).toEqual(config); }); it("should reject empty integrator ID", () => { const config = { SQUID_INTEGRATOR_ID: "", SQUID_SDK_URL: "https://api.squid.com", SQUID_EVM_ADDRESS: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", SQUID_EVM_PRIVATE_KEY: "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", }; expect(() => squidRouterEnvSchema.parse(config)).toThrow(); }); it("should validate EVM address checksum", () => { const config = { SQUID_INTEGRATOR_ID: "test-id", SQUID_SDK_URL: "https://api.squid.com", SQUID_EVM_ADDRESS: "0x742d35cc6634c0532925a3b844bc9e7595f62999", // lowercase SQUID_EVM_PRIVATE_KEY: "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", }; // ethers.isAddress accepts both checksummed and non-checksummed addresses const result = squidRouterEnvSchema.parse(config); expect(result).toBeDefined(); }); it("should validate private key length", () => { const config = { SQUID_INTEGRATOR_ID: "test-id", SQUID_SDK_URL: "https://api.squid.com", SQUID_EVM_ADDRESS: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", SQUID_EVM_PRIVATE_KEY: "0x123", // too short }; expect(() => squidRouterEnvSchema.parse(config)).toThrow( "64-character hexadecimal" ); }); it("should validate private key contains only hex characters", () => { const config = { SQUID_INTEGRATOR_ID: "test-id", SQUID_SDK_URL: "https://api.squid.com", SQUID_EVM_ADDRESS: "0x742D35Cc6634c0532925A3b844BC9E7595f6F269", SQUID_EVM_PRIVATE_KEY: "0xGGGG456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", // invalid hex }; expect(() => squidRouterEnvSchema.parse(config)).toThrow( "64-character hexadecimal" ); }); });