harb/kraiken-lib/src/tests/snatch.test.ts
2025-10-01 14:43:55 +02:00

81 lines
2.4 KiB
TypeScript

import { describe, expect, test } from "@jest/globals";
import {
getSnatchList,
minimumTaxRate,
selectSnatchPositions,
type SnatchablePosition,
} from "../snatch";
import { uint256ToBytesLittleEndian } from "../subgraph";
import type { Position } from "../__generated__/graphql";
import { PositionStatus } from "../__generated__/graphql";
describe("snatch", () => {
test("minimumTaxRate finds the lowest tax", () => {
const rates = [{ taxRate: 0.12 }, { taxRate: 0.05 }, { taxRate: 0.08 }];
expect(minimumTaxRate(rates, 1)).toBeCloseTo(0.05);
expect(minimumTaxRate([], 0.42)).toBe(0.42);
});
test("selectSnatchPositions chooses cheapest positions first", () => {
const candidates: SnatchablePosition[] = [
{ id: 1n, stakeShares: 30n, taxRate: 0.05, taxRateIndex: 5 },
{ id: 2n, stakeShares: 40n, taxRate: 0.03, taxRateIndex: 3 },
{ id: 3n, stakeShares: 50n, taxRate: 0.07, taxRateIndex: 7 },
];
const result = selectSnatchPositions(candidates, {
shortfallShares: 60n,
maxTaxRate: 0.08,
});
expect(result.selected.map((item) => item.id)).toEqual([2n, 1n]);
expect(result.remainingShortfall).toBe(0n);
expect(result.coveredShares).toBe(60n);
expect(result.maxSelectedTaxRateIndex).toBe(5);
});
test("selectSnatchPositions keeps track of remaining shortfall", () => {
const candidates: SnatchablePosition[] = [
{ id: 1n, stakeShares: 10n, taxRate: 0.01 },
{ id: 2n, stakeShares: 10n, taxRate: 0.02 },
];
const result = selectSnatchPositions(candidates, {
shortfallShares: 50n,
maxTaxRate: 0.05,
});
expect(result.remainingShortfall).toBe(30n);
});
test("getSnatchList converts subgraph positions", () => {
const stakeTotalSupply = 1_000_000n * 10n ** 18n;
const positions: Position[] = [
{
__typename: "Position",
id: uint256ToBytesLittleEndian(1n),
owner: "0xowner1",
share: 0.0001,
creationTime: 0,
lastTaxTime: 0,
taxRate: 0.02,
status: PositionStatus.Active,
},
{
__typename: "Position",
id: uint256ToBytesLittleEndian(2n),
owner: "0xowner2",
share: 0.0002,
creationTime: 0,
lastTaxTime: 0,
taxRate: 0.01,
status: PositionStatus.Active,
},
];
const result = getSnatchList(positions, 10n ** 18n, 0.05, stakeTotalSupply);
expect(result).toEqual([2n]);
});
});