src/transport/contracts.test.ts
v0.2.0 · 2.9 KB
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
import { describe, expect, it } from 'vitest';
import { createNetworkVerifier, parseContracts, verifyNetwork } from './contracts.js';
import { NadoNetworkMismatchError } from './errors.js';
import { CHAIN_ID, type QueryRequester } from './types.js';
const endpoint = privateKeyToAccount(generatePrivateKey()).address; // stands in for endpoint_addr
const lower = endpoint.toLowerCase();
function queryOf(data: unknown | (() => unknown)): { query: QueryRequester; calls: number } {
const state = { calls: 0 };
const query: QueryRequester = async <T>(body: { type: string }) => {
state.calls++;
expect(body.type).toBe('contracts');
const d = typeof data === 'function' ? (data as () => unknown)() : data;
return d as T;
};
return {
query,
get calls() {
return state.calls;
},
};
}
describe('parseContracts', () => {
it('reads chain_id and lower-cases endpoint_addr', () => {
expect(parseContracts({ chain_id: 57073, endpoint_addr: endpoint })).toEqual({
chainId: 57073,
endpointAddr: lower,
});
expect(parseContracts({ chain_id: '763373', endpoint_addr: lower })).toEqual({
chainId: 763373,
endpointAddr: lower,
});
});
it('fails closed on junk', () => {
expect(() => parseContracts({ chain_id: 0, endpoint_addr: endpoint })).toThrow(/chain_id/);
expect(() => parseContracts({ chain_id: 'x', endpoint_addr: endpoint })).toThrow(/chain_id/);
expect(() => parseContracts({ chain_id: 57073, endpoint_addr: '0x12' })).toThrow(/endpoint_addr/);
expect(() => parseContracts(null)).toThrow(/chain_id/);
});
});
describe('verifyNetwork / createNetworkVerifier', () => {
it('accepts the expected chain id and refuses the other network', async () => {
const ok = queryOf({ chain_id: CHAIN_ID.mainnet, endpoint_addr: endpoint });
await expect(verifyNetwork(ok.query, CHAIN_ID.mainnet)).resolves.toEqual({ chainId: 57073, endpointAddr: lower });
const wrong = queryOf({ chain_id: CHAIN_ID.testnet, endpoint_addr: endpoint });
await expect(verifyNetwork(wrong.query, CHAIN_ID.mainnet, { url: 'https://x' })).rejects.toBeInstanceOf(
NadoNetworkMismatchError,
);
});
it('caches a success, single-flights concurrent callers and retries after a failure', async () => {
let fail = true;
const q = queryOf(() => {
if (fail) throw new Error('network');
return { chain_id: CHAIN_ID.mainnet, endpoint_addr: endpoint };
});
const v = createNetworkVerifier(q.query, CHAIN_ID.mainnet);
expect(v.peek()).toBeNull();
await expect(v.get()).rejects.toThrow('network');
expect(v.peek()).toBeNull();
fail = false;
const [a, b] = await Promise.all([v.get(), v.get()]);
expect(a).toBe(b);
expect(q.calls).toBe(2);
await v.get();
expect(q.calls).toBe(2);
expect(v.peek()?.endpointAddr).toBe(lower);
});
});