Files
strategic/tests/unit/guards/twapSanity.test.ts
2026-02-09 21:51:54 -08:00

89 lines
2.5 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
import { evaluateTWAPSanity } from "../../../src/guards/twapSanity.js";
import { UniswapV3Adapter } from "../../../src/adapters/uniswapV3.js";
import { Guard } from "../../../src/strategy.schema.js";
describe("TWAP Sanity Guard", () => {
let mockUniswap: UniswapV3Adapter;
let mockProvider: any;
beforeEach(() => {
mockProvider = {
getNetwork: vi.fn().mockResolvedValue({ chainId: 1n }),
call: vi.fn(),
};
mockUniswap = new UniswapV3Adapter("mainnet");
// @ts-ignore - access private property for testing
mockUniswap.provider = mockProvider;
});
it("should pass when TWAP is within deviation", async () => {
const guard: Guard = {
type: "twapSanity",
params: {
tokenIn: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
tokenOut: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
fee: 3000,
maxDeviationBps: 500, // 5%
},
};
const context = {
amountIn: 1000000n,
expectedAmountOut: 1000000n,
};
// Mock quote that's within deviation
vi.spyOn(mockUniswap, "quoteExactInput").mockResolvedValue(1010000n); // 1% deviation
const result = await evaluateTWAPSanity(guard, mockUniswap, context);
expect(result.passed).toBe(true);
});
it("should fail when TWAP deviation is too high", async () => {
const guard: Guard = {
type: "twapSanity",
params: {
tokenIn: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
tokenOut: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
fee: 3000,
maxDeviationBps: 100, // 1%
},
};
const context = {
amountIn: 1000000n,
expectedAmountOut: 1000000n,
};
// Mock quote that's 2% off
vi.spyOn(mockUniswap, "quoteExactInput").mockResolvedValue(980000n); // 2% deviation
const result = await evaluateTWAPSanity(guard, mockUniswap, context);
expect(result.passed).toBe(false);
expect(result.reason).toContain("deviation");
});
it("should handle missing pool gracefully", async () => {
const guard: Guard = {
type: "twapSanity",
params: {
tokenIn: "0xInvalid",
tokenOut: "0xInvalid",
fee: 3000,
maxDeviationBps: 500,
},
};
vi.spyOn(mockUniswap, "quoteExactInput").mockRejectedValue(
new Error("Pool not found")
);
const result = await evaluateTWAPSanity(guard, mockUniswap, {});
expect(result.passed).toBe(false);
expect(result.reason).toBeDefined();
});
});