import { Fraction } from '@uniswap/sdk-core'; import { PoolSharkCustomRouter, calculateAmountToSwap, fractionAbsoluteValue, } from '../../src/routers/poolshark/poolshark-router'; const makePool = (overrides: Record = {}) => ({ token0: jest.fn().mockResolvedValue('0x1'), token1: jest.fn().mockResolvedValue('0x2'), tickSpacing: jest.fn().mockResolvedValue(10), globalState: jest.fn().mockResolvedValue({ unlocked: true, pool: { price: 79228162514264337593543950336n }, }), ...overrides, }); const makeQuoter = () => ({ quote: jest.fn().mockResolvedValue([0n, 1n, 2n]), }); describe('PoolShark router helpers', () => { it('fractionAbsoluteValue returns positive numerator and denominator', () => { const frac = new Fraction(-6, 7); const abs = fractionAbsoluteValue(frac); expect(abs.numerator.toString()).toBe('6'); expect(abs.denominator.toString()).toBe('7'); }); it('calculateAmountToSwap handles zero and infinite ratios', () => { const zeroRatio = new Fraction(0, 1); expect(calculateAmountToSwap(zeroRatio, 1n, true, 7n, 3n)).toBe(7n); expect(() => calculateAmountToSwap(zeroRatio, 1n, false, 7n, 3n)).toThrow( 'wrong parameters', ); const infRatio = new Fraction(1, 0); expect(calculateAmountToSwap(infRatio, 1n, false, 7n, 3n)).toBe(3n); expect(() => calculateAmountToSwap(infRatio, 1n, true, 7n, 3n)).toThrow( 'wrong parameters', ); }); }); describe('PoolSharkCustomRouter', () => { const positions = [{ lowerTick: -60, upperTick: 60, weight: 1 }]; beforeEach(() => { jest.spyOn(console, 'log').mockImplementation(() => undefined); }); afterEach(() => { (console.log as jest.Mock).mockRestore(); }); it('returns zero when already balanced', async () => { const pool = makePool(); const quoter = makeQuoter(); const router = new PoolSharkCustomRouter(quoter as any, {} as any); const result = await router.getSwapAmount( pool as any, positions as any, 1n, 1n, '0x1', '0x2', 1, new Fraction(1, 1), ); expect(result).toEqual({ amountToSwap: 0n, zeroForOne: false }); }); it('returns undefined when iterations complete without match', async () => { const pool = makePool(); const quoter = makeQuoter(); const router = new PoolSharkCustomRouter(quoter as any, {} as any); const result = await router.getSwapAmount( pool as any, positions as any, 100n, 1n, '0x1', '0x2', 1, new Fraction(0, 1), ); expect(result).toBeUndefined(); }); it('throws when pool is not initialized', async () => { const pool = makePool({ globalState: jest .fn() .mockResolvedValue({ unlocked: false, pool: { price: 1n } }), }); const quoter = makeQuoter(); const router = new PoolSharkCustomRouter(quoter as any, {} as any); await expect( router.getSwapAmount( pool as any, positions as any, 1n, 1n, '0x1', '0x2', 1, ), ).rejects.toThrow('Pool is not initialized'); }); it('throws on invalid params for desired positions', async () => { const pool = makePool(); const quoter = makeQuoter(); const router = new PoolSharkCustomRouter(quoter as any, {} as any); await expect( router.getSwapAmount( pool as any, [{ lowerTick: -60, upperTick: -60, weight: 1 }] as any, 10n, 20n, '0x1', '0x2', 1, ), ).rejects.toThrow('lowerTick must be less than upperTick'); }); it('throws when maxIterations is not positive', async () => { const pool = makePool(); const quoter = makeQuoter(); const router = new PoolSharkCustomRouter(quoter as any, {} as any); await expect( router.getSwapAmount( pool as any, positions as any, 10n, 20n, '0x1', '0x2', 0, ), ).rejects.toThrow('maxIterations must be greater than 0'); }); });