import { describe, it, expect, beforeAll } from "vitest"; import { StrategyCompiler } from "../../src/planner/compiler.js"; import { loadStrategy, substituteBlinds } from "../../src/strategy.js"; import { getChainConfig } from "../../src/config/chains.js"; import { JsonRpcProvider, Contract, getAddress } from "ethers"; import { join } from "path"; import * as dotenv from "dotenv"; // Load environment variables dotenv.config(); describe("Protocol Integration Tests - Recursive Leverage Strategy", () => { const RPC_MAINNET = process.env.RPC_MAINNET; const RPC_POLYGON = process.env.RPC_POLYGON; const RPC_BASE = process.env.RPC_BASE; const RPC_OPTIMISM = process.env.RPC_OPTIMISM; // Aave v3 Pool contract ABI (minimal for testing) const AAVE_POOL_ABI = [ "function getReserveData(address asset) external view returns (tuple(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint40))", "function getReservesList() external view returns (address[])", ]; describe("Mainnet Protocol Contracts", () => { it.skipIf(!RPC_MAINNET)("should connect to Aave v3 Pool on mainnet", async () => { const provider = new JsonRpcProvider(RPC_MAINNET); const chainConfig = getChainConfig("mainnet"); if (!chainConfig.protocols.aaveV3?.pool) { throw new Error("Aave v3 pool address not configured"); } const poolAddress = getAddress(chainConfig.protocols.aaveV3.pool); const poolContract = new Contract(poolAddress, AAVE_POOL_ABI, provider); // Test connection by calling getReservesList const reserves = await poolContract.getReservesList(); expect(reserves).toBeDefined(); expect(Array.isArray(reserves)).toBe(true); expect(reserves.length).toBeGreaterThan(0); }); it.skipIf(!RPC_MAINNET)("should verify Aave v3 Pool address is correct", async () => { const provider = new JsonRpcProvider(RPC_MAINNET); const chainConfig = getChainConfig("mainnet"); if (!chainConfig.protocols.aaveV3?.pool) { throw new Error("Aave v3 pool address not configured"); } const poolAddress = getAddress(chainConfig.protocols.aaveV3.pool); // Verify contract exists by checking code const code = await provider.getCode(poolAddress); expect(code).not.toBe("0x"); expect(code.length).toBeGreaterThan(2); }); it.skipIf(!RPC_MAINNET)("should compile recursive leverage strategy with real protocol addresses", async () => { const strategyPath = join( process.cwd(), "strategies", "sample.recursive.json" ); if (!require("fs").existsSync(strategyPath)) { return; } const strategy = loadStrategy(strategyPath); // Substitute blind values for testing const blindValues = { collateralAmount: "1000000", // 1 USDC (6 decimals) leverageFactor: "500000", // 0.5 USDC }; const resolvedStrategy = substituteBlinds(strategy, blindValues); const compiler = new StrategyCompiler(resolvedStrategy.chain); const plan = await compiler.compile(resolvedStrategy); expect(plan.calls.length).toBeGreaterThan(0); // Verify the compiled calls target the correct Aave pool address const chainConfig = getChainConfig("mainnet"); const aavePoolAddress = chainConfig.protocols.aaveV3?.pool; if (aavePoolAddress) { const checksummedPoolAddress = getAddress(aavePoolAddress); const supplyCall = plan.calls.find(call => getAddress(call.to).toLowerCase() === checksummedPoolAddress.toLowerCase() ); expect(supplyCall).toBeDefined(); expect(supplyCall?.description).toContain("Aave"); } }); it.skipIf(!RPC_MAINNET)("should verify USDC is a valid reserve in Aave v3", async () => { const provider = new JsonRpcProvider(RPC_MAINNET); const chainConfig = getChainConfig("mainnet"); if (!chainConfig.protocols.aaveV3?.pool) { throw new Error("Aave v3 pool address not configured"); } const poolAddress = getAddress(chainConfig.protocols.aaveV3.pool); const poolContract = new Contract(poolAddress, AAVE_POOL_ABI, provider); // USDC address on mainnet const USDC_ADDRESS = getAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"); // Get reserve data for USDC const reserveData = await poolContract.getReserveData(USDC_ADDRESS); expect(reserveData).toBeDefined(); // Verify it's a valid reserve (liquidityIndex should be > 0) const liquidityIndex = reserveData[0]; expect(liquidityIndex).toBeDefined(); expect(Number(liquidityIndex)).toBeGreaterThan(0); }); it.skipIf(!RPC_MAINNET)("should verify Uniswap V3 Router address", async () => { const provider = new JsonRpcProvider(RPC_MAINNET); const chainConfig = getChainConfig("mainnet"); if (!chainConfig.protocols.uniswapV3?.router) { throw new Error("Uniswap V3 router address not configured"); } const routerAddress = getAddress(chainConfig.protocols.uniswapV3.router); // Verify contract exists const code = await provider.getCode(routerAddress); expect(code).not.toBe("0x"); expect(code.length).toBeGreaterThan(2); }); }); describe("Polygon Protocol Contracts", () => { it.skipIf(!RPC_POLYGON)("should connect to Polygon RPC and verify chain config", async () => { const provider = new JsonRpcProvider(RPC_POLYGON); // Note: Polygon chain config may not be implemented yet // This test verifies RPC connectivity only // Verify we can connect const blockNumber = await provider.getBlockNumber(); expect(blockNumber).toBeGreaterThan(0); // Verify chain ID matches Polygon const network = await provider.getNetwork(); expect(network.chainId).toBe(BigInt(137)); }); }); describe("Base Protocol Contracts", () => { it.skipIf(!RPC_BASE)("should connect to Base RPC and verify chain config", async () => { const provider = new JsonRpcProvider(RPC_BASE); const chainConfig = getChainConfig("base"); // Verify we can connect const blockNumber = await provider.getBlockNumber(); expect(blockNumber).toBeGreaterThan(0); // Verify chain ID matches const network = await provider.getNetwork(); expect(network.chainId).toBe(BigInt(8453)); }); }); describe("Optimism Protocol Contracts", () => { it.skipIf(!RPC_OPTIMISM)("should connect to Optimism RPC and verify chain config", async () => { const provider = new JsonRpcProvider(RPC_OPTIMISM); const chainConfig = getChainConfig("optimism"); // Verify we can connect const blockNumber = await provider.getBlockNumber(); expect(blockNumber).toBeGreaterThan(0); // Verify chain ID matches const network = await provider.getNetwork(); expect(network.chainId).toBe(BigInt(10)); }); }); describe("Recursive Leverage Strategy - Full Integration", () => { it.skipIf(!RPC_MAINNET)("should compile and validate recursive leverage strategy against real contracts", async () => { const strategyPath = join( process.cwd(), "strategies", "sample.recursive.json" ); if (!require("fs").existsSync(strategyPath)) { return; } const provider = new JsonRpcProvider(RPC_MAINNET); const strategy = loadStrategy(strategyPath); const chainConfig = getChainConfig(strategy.chain); // Substitute blind values const blindValues = { collateralAmount: "1000000", // 1 USDC leverageFactor: "500000", // 0.5 USDC }; const resolvedStrategy = substituteBlinds(strategy, blindValues); // Compile strategy const compiler = new StrategyCompiler(resolvedStrategy.chain); const plan = await compiler.compile(resolvedStrategy); expect(plan.calls.length).toBeGreaterThan(0); // Verify all calls target valid contract addresses for (const call of plan.calls) { const callAddress = getAddress(call.to); const code = await provider.getCode(callAddress); expect(code).not.toBe("0x"); expect(code.length).toBeGreaterThan(2); } // Verify Aave pool address matches configuration const aavePoolAddress = chainConfig.protocols.aaveV3?.pool; if (aavePoolAddress) { const checksummedPoolAddress = getAddress(aavePoolAddress); const aaveCalls = plan.calls.filter(call => getAddress(call.to).toLowerCase() === checksummedPoolAddress.toLowerCase() ); expect(aaveCalls.length).toBeGreaterThan(0); } }); }); });