import { Fraction } from '@uniswap/sdk-core'; import { ThickV2CustomRouter, calculateAmountToSwap, fractionAbsoluteValue, } from '../../src/routers/thickv2/thickv2-router'; jest.mock('../../src/routers/base/base-router', () => { return { BaseRouter: jest.fn().mockImplementation(() => ({ getSwapAmount: jest .fn() .mockResolvedValue({ amountToSwap: 5n, zeroForOne: true }), })), }; }); const makePool = (overrides: Record = {}) => ({ slot0: jest .fn() .mockResolvedValue({ sqrtPriceX96: 79228162514264337593543950336n }), ...overrides, }); const makeQuoter = () => ({ callStatic: { quoteExactInputSingle: jest.fn().mockResolvedValue({ amountOut: 1n, sqrtPriceX96After: 2n, }), }, }); describe('ThickV2 router helpers', () => { it('fractionAbsoluteValue returns positive numerator and denominator', () => { const frac = new Fraction(-10, 11); const abs = fractionAbsoluteValue(frac); expect(abs.numerator.toString()).toBe('10'); expect(abs.denominator.toString()).toBe('11'); }); it('calculateAmountToSwap handles zero and infinite ratios', () => { const zeroRatio = new Fraction(0, 1); expect(calculateAmountToSwap(zeroRatio, 1n, true, 5n, 2n)).toBe(5n); expect(() => calculateAmountToSwap(zeroRatio, 1n, false, 5n, 2n)).toThrow( 'wrong parameters', ); const infRatio = new Fraction(1, 0); expect(calculateAmountToSwap(infRatio, 1n, false, 5n, 2n)).toBe(2n); expect(() => calculateAmountToSwap(infRatio, 1n, true, 5n, 2n)).toThrow( 'wrong parameters', ); }); }); describe('ThickV2CustomRouter', () => { const positions = [{ lowerTick: -60, upperTick: 60, weight: 1 }]; it('uses fallback when legacy flow fails', async () => { const pool = makePool({ slot0: jest.fn().mockResolvedValue({ sqrtPriceX96: 79228162514264337593543950336n, }), }); const quoter = makeQuoter(); const logger = { info: jest.fn() } as any; const router = new ThickV2CustomRouter(quoter as any, logger); const result = await router.getSwapAmount( pool as any, positions as any, 10n, 20n, '0x1', '0x2', 10, 2, ); const baseRouterModule = require('../../src/routers/base/base-router'); const baseRouterInstance = baseRouterModule.BaseRouter.mock.results[0].value; expect(baseRouterInstance.getSwapAmount).toHaveBeenCalled(); expect(result).toEqual({ amountToSwap: 5n, zeroForOne: true }); }); it('throws when fallback fails', async () => { const baseRouterModule = require('../../src/routers/base/base-router'); baseRouterModule.BaseRouter.mockImplementationOnce(() => ({ getSwapAmount: jest.fn().mockRejectedValue(new Error('fallback failed')), })); const pool = makePool(); const quoter = makeQuoter(); const logger = { info: jest.fn() } as any; const router = new ThickV2CustomRouter(quoter as any, logger); await expect( router.getSwapAmount( pool as any, positions as any, 10n, 20n, '0x1', '0x2', 10, 2, ), ).rejects.toThrow('fallback failed'); }); });