harb/kraiken-lib/src/tests/staking.test.ts
openhands 26a9645b1f fix: kraiken-lib: fix broken tests + raise coverage to 95% (#286)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 00:10:45 +00:00

76 lines
2.9 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import { calculateSnatchShortfall, isPositionDelinquent } from '../staking.js';
describe('calculateSnatchShortfall', () => {
test('returns zero when within cap', () => {
const outstanding = 100n;
const desired = 50n;
const total = 1000n;
const result = calculateSnatchShortfall(outstanding, desired, total, 2n, 10n);
expect(result).toBe(0n);
});
test('returns positive remainder when exceeding cap', () => {
const outstanding = 200n;
const desired = 200n;
const total = 1000n;
const result = calculateSnatchShortfall(outstanding, desired, total, 2n, 10n);
expect(result).toBe(200n);
});
test('returns exact overage when required equals cap + 1', () => {
// cap = (1000 * 2) / 10 = 200; required = 100 + 101 = 201; delta = 1
expect(calculateSnatchShortfall(100n, 101n, 1000n, 2n, 10n)).toBe(1n);
});
test('returns zero when required equals cap exactly', () => {
// cap = (1000 * 2) / 10 = 200; required = 100 + 100 = 200; delta = 0
expect(calculateSnatchShortfall(100n, 100n, 1000n, 2n, 10n)).toBe(0n);
});
test('uses default cap numerator/denominator when not provided', () => {
// defaults: capNumerator=2n, capDenominator=10n
// cap = (1000 * 2) / 10 = 200; outstanding=100, desired=50 -> required=150 <= 200 -> 0
expect(calculateSnatchShortfall(100n, 50n, 1000n)).toBe(0n);
});
test('throws when capDenominator is zero', () => {
expect(() => calculateSnatchShortfall(100n, 50n, 1000n, 2n, 0n)).toThrow('capDenominator must be greater than zero');
});
});
describe('isPositionDelinquent', () => {
test('respects tax rate windows', () => {
const now = 1_000_000;
const taxRate = 0.5; // 50%
const windowSeconds = (365 * 24 * 60 * 60) / taxRate;
expect(isPositionDelinquent(now - windowSeconds + 1, taxRate, now)).toBe(false);
expect(isPositionDelinquent(now - windowSeconds - 10, taxRate, now)).toBe(true);
expect(isPositionDelinquent(now, 0, now)).toBe(false);
});
test('returns false for zero tax rate', () => {
expect(isPositionDelinquent(0, 0, 1_000_000)).toBe(false);
});
test('returns false for negative tax rate', () => {
expect(isPositionDelinquent(0, -0.1, 1_000_000)).toBe(false);
});
test('returns true when far past the allowance window', () => {
// taxRate=1.0 -> allowance = 31_536_000s (1 year); use now > 31_536_000
const now = 100_000_000;
const lastTax = 0;
const taxRate = 1.0; // 100% per year = 1 year window
expect(isPositionDelinquent(lastTax, taxRate, now)).toBe(true);
});
test('uses current time as default when referenceTimestamp not provided', () => {
// taxRate=1.0 -> allowance = 1 year; 2 years ago is definitely delinquent
const twoYearsAgoSeconds = Math.floor(Date.now() / 1000) - 2 * 365 * 24 * 60 * 60;
expect(isPositionDelinquent(twoYearsAgoSeconds, 1.0)).toBe(true);
});
});