src/account/fees.test.ts
v0.3.0 · 3 KB
import { describe, expect, it } from 'vitest';
import type { InfoCallOptions, InfoRequest, InfoRequester } from '../transport/types.js';
import { fetchUserFees, parseUserFees } from './fees.js';
const USER = `0x${'0'.repeat(38)}Ab`;
describe('parseUserFees', () => {
it('userAddRate is maker, userCrossRate is taker; bps computed exactly', () => {
const f = parseUserFees({ userAddRate: '0.00015', userCrossRate: '0.00045', activeReferralDiscount: '0.0' });
expect(f.makerRate).toBe(0.00015);
expect(f.takerRate).toBe(0.00045);
expect(f.makerBps).toBe(1.5);
expect(f.takerBps).toBe(4.5);
expect(f.exact).toEqual({ makerRate: '0.00015', takerRate: '0.00045', makerBps: '1.5', takerBps: '4.5', referralDiscount: '0' });
});
it('rates that float multiplication would distort stay exact', () => {
const f = parseUserFees({ userAddRate: '0.00007', userCrossRate: '0.00028' });
expect(f.makerBps).toBe(0.7);
expect(f.takerBps).toBe(2.8);
});
it('supports maker rebates (negative rates)', () => {
expect(parseUserFees({ userAddRate: '-0.00002', userCrossRate: '0.00025' }).makerBps).toBe(-0.2);
});
it('referral discount defaults to 0 and is parsed when present', () => {
expect(parseUserFees({ userAddRate: '0', userCrossRate: '0' }).referralDiscount).toBe(0);
expect(parseUserFees({ userAddRate: '0', userCrossRate: '0', activeReferralDiscount: '0.04' }).referralDiscount).toBe(0.04);
});
it('spot rates are optional', () => {
const f = parseUserFees({ userAddRate: '0.0001', userCrossRate: '0.0003', userSpotAddRate: '0.0004', userSpotCrossRate: '0.0007' });
expect([f.spotMakerRate, f.spotTakerRate]).toEqual([0.0004, 0.0007]);
expect(parseUserFees({ userAddRate: '0.0001', userCrossRate: '0.0003' }).spotMakerRate).toBeNull();
});
it('malformed answers throw', () => {
expect(() => parseUserFees(null)).toThrow(expect.objectContaining({ code: 'INVALID_RESPONSE' }));
expect(() => parseUserFees({ userAddRate: 0.00015, userCrossRate: '0.00045' })).toThrow(/userAddRate/);
expect(() => parseUserFees({ userAddRate: '0.00015' })).toThrow(/userCrossRate/);
expect(() => parseUserFees({ userAddRate: '0', userCrossRate: '0', activeReferralDiscount: 'x' })).toThrow(/Referral/i);
});
});
describe('fetchUserFees', () => {
it('requests userFees for the lowercased account', async () => {
const calls: InfoRequest[] = [];
const info = (async (body: InfoRequest, _opts?: InfoCallOptions) => {
calls.push(body);
return { userAddRate: '0.00015', userCrossRate: '0.00045', activeReferralDiscount: '0.0' };
}) as InfoRequester;
const f = await fetchUserFees(info, USER);
expect(calls).toEqual([{ type: 'userFees', user: USER.toLowerCase() }]);
expect(f.takerBps).toBe(4.5);
});
it('rejects a malformed address without a request', async () => {
const info = (async () => {
throw new Error('should not be called');
}) as InfoRequester;
await expect(fetchUserFees(info, '0xYOUR_ADDRESS')).rejects.toMatchObject({ code: 'INVALID_ARGUMENT' });
});
});