import { describe, it, expect } from "vitest"; import { StrategyCompiler } from "../../../src/planner/compiler.js"; import { Strategy } from "../../../src/strategy.schema.js"; describe("Strategy Compiler", () => { const executorAddr = "0x1234567890123456789012345678901234567890"; it("should compile aaveV3.supply", async () => { const compiler = new StrategyCompiler("mainnet"); const strategy: Strategy = { name: "Test", chain: "mainnet", steps: [{ id: "supply", action: { type: "aaveV3.supply", asset: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", amount: "1000000", }, }], }; const plan = await compiler.compile(strategy, executorAddr); expect(plan.calls.length).toBe(1); expect(plan.calls[0].description).toContain("Aave v3 supply"); }); it("should compile aaveV3.setUserEMode", async () => { const compiler = new StrategyCompiler("mainnet"); const strategy: Strategy = { name: "Test", chain: "mainnet", steps: [{ id: "setEMode", action: { type: "aaveV3.setUserEMode", categoryId: 1, }, }], }; const plan = await compiler.compile(strategy, executorAddr); expect(plan.calls.length).toBe(1); }); it("should compile maker.openVault", async () => { const compiler = new StrategyCompiler("mainnet"); const strategy: Strategy = { name: "Test", chain: "mainnet", steps: [{ id: "openVault", action: { type: "maker.openVault", ilk: "ETH-A", }, }], }; const plan = await compiler.compile(strategy, executorAddr); expect(plan.calls.length).toBe(1); }); it("should compile balancer.batchSwap", async () => { const compiler = new StrategyCompiler("mainnet"); const strategy: Strategy = { name: "Test", chain: "mainnet", steps: [{ id: "batchSwap", action: { type: "balancer.batchSwap", kind: "givenIn", swaps: [{ poolId: "0x...", assetInIndex: 0, assetOutIndex: 1, amount: "1000000", }], assets: [ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "0xdAC17F958D2ee523a2206206994597C13D831ec7", ], }, }], }; const plan = await compiler.compile(strategy, executorAddr); expect(plan.calls.length).toBe(1); }); it("should compile curve.exchange_underlying", async () => { const compiler = new StrategyCompiler("mainnet"); const strategy: Strategy = { name: "Test", chain: "mainnet", steps: [{ id: "exchange", action: { type: "curve.exchange_underlying", pool: "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7", i: 0, j: 1, dx: "1000000", }, }], }; const plan = await compiler.compile(strategy, executorAddr); expect(plan.calls.length).toBe(1); }); it("should compile aggregators.swap1Inch", async () => { const compiler = new StrategyCompiler("mainnet"); const strategy: Strategy = { name: "Test", chain: "mainnet", steps: [{ id: "swap", action: { type: "aggregators.swap1Inch", tokenIn: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", tokenOut: "0xdAC17F958D2ee523a2206206994597C13D831ec7", amountIn: "1000000", }, }], }; // Mock 1inch API global.fetch = vi.fn().mockResolvedValue({ ok: true, json: async () => ({ toAmount: "1000000", tx: { data: "0x1234" }, }), }); const plan = await compiler.compile(strategy, executorAddr); expect(plan.calls.length).toBe(1); }); it("should compile perps.increasePosition", async () => { const compiler = new StrategyCompiler("mainnet"); const strategy: Strategy = { name: "Test", chain: "mainnet", steps: [{ id: "increase", action: { type: "perps.increasePosition", path: ["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"], indexToken: "0xdAC17F958D2ee523a2206206994597C13D831ec7", amountIn: "1000000", sizeDelta: "2000000", isLong: true, }, }], }; const plan = await compiler.compile(strategy, executorAddr); expect(plan.calls.length).toBe(1); }); it("should wrap flash loan with subsequent operations", async () => { const compiler = new StrategyCompiler("mainnet"); const strategy: Strategy = { name: "Flash Loan", chain: "mainnet", steps: [ { id: "flashLoan", action: { type: "aaveV3.flashLoan", assets: ["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"], amounts: ["1000000"], }, }, { id: "swap", action: { type: "uniswapV3.swap", tokenIn: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", tokenOut: "0xdAC17F958D2ee523a2206206994597C13D831ec7", fee: 3000, amountIn: "1000000", exactInput: true, }, }, ], }; const plan = await compiler.compile(strategy, executorAddr); expect(plan.requiresFlashLoan).toBe(true); expect(plan.flashLoanAsset).toBe("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"); // Should have executeFlashLoan call expect(plan.calls.some(c => c.description.includes("flash loan"))).toBe(true); }); it("should substitute executor address in swaps", async () => { const compiler = new StrategyCompiler("mainnet"); const strategy: Strategy = { name: "Test", chain: "mainnet", steps: [{ id: "swap", action: { type: "uniswapV3.swap", tokenIn: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", tokenOut: "0xdAC17F958D2ee523a2206206994597C13D831ec7", fee: 3000, amountIn: "1000000", exactInput: true, }, }], }; const plan = await compiler.compile(strategy, executorAddr); // Recipient should be executor address, not zero expect(plan.calls.length).toBe(1); }); });