Skip to content

Commit 70ac10a

Browse files
Refactor get-network logic to be more testable
1 parent 26dd6f2 commit 70ac10a

File tree

3 files changed

+139
-103
lines changed

3 files changed

+139
-103
lines changed

packages/cre-sdk/src/sdk/utils/chain-selectors/get-network.test.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { afterAll, describe, expect, it, mock } from 'bun:test'
1+
import { describe, expect, it } from 'bun:test'
2+
import { NetworkLookup } from './network-lookup'
23

34
// Mock the generated networks module with deterministic fixtures
4-
const mockModulePath = '@cre/generated/networks'
5+
// We are not using mock.module anymore, but constructing the lookup class directly
56

67
const evmMain = {
78
chainId: '1',
@@ -85,8 +86,7 @@ const testnetByNameByFamily = {
8586
tron: new Map(),
8687
} as const
8788

88-
// Install module mock before importing the SUT
89-
mock.module(mockModulePath, () => ({
89+
const lookup = new NetworkLookup({
9090
mainnetByName,
9191
mainnetByNameByFamily,
9292
mainnetBySelector,
@@ -95,15 +95,10 @@ mock.module(mockModulePath, () => ({
9595
testnetByNameByFamily,
9696
testnetBySelector,
9797
testnetBySelectorByFamily,
98-
}))
99-
100-
const { getNetwork } = await import('./get-network')
101-
102-
// Clean up the mock after all tests to prevent interference with other test files
103-
afterAll(() => {
104-
mock.restore()
10598
})
10699

100+
const getNetwork = (opts: any) => lookup.find(opts)
101+
107102
describe('getNetwork', () => {
108103
it('returns undefined when neither chainSelector nor chainSelectorName provided', () => {
109104
expect(getNetwork({})).toBeUndefined()

packages/cre-sdk/src/sdk/utils/chain-selectors/get-network.ts

Lines changed: 14 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -8,102 +8,24 @@ import {
88
testnetBySelector,
99
testnetBySelectorByFamily,
1010
} from '@cre/generated/networks'
11-
import type { ChainFamily, NetworkInfo } from './types'
11+
import { type GetNetworkOptions, NetworkLookup } from './network-lookup'
12+
import type { NetworkInfo } from './types'
1213

13-
interface GetNetworkOptions {
14-
chainSelector?: bigint
15-
chainSelectorName?: string
16-
isTestnet?: boolean | undefined
17-
chainFamily?: ChainFamily
18-
}
14+
const defaultLookup = new NetworkLookup({
15+
mainnetByName,
16+
mainnetByNameByFamily,
17+
mainnetBySelector,
18+
mainnetBySelectorByFamily,
19+
testnetByName,
20+
testnetByNameByFamily,
21+
testnetBySelector,
22+
testnetBySelectorByFamily,
23+
})
1924

2025
/**
2126
* High-performance network lookup using Maps for O(1) performance
2227
* @param options - Search criteria
2328
* @returns NetworkInfo if found, undefined otherwise
2429
*/
25-
export const getNetwork = (options: GetNetworkOptions): NetworkInfo | undefined => {
26-
const { chainSelector, chainSelectorName, isTestnet, chainFamily } = options
27-
28-
const getBySelector = (map: Map<bigint, NetworkInfo>) => {
29-
if (chainSelector === undefined) return undefined
30-
return map.get(chainSelector)
31-
}
32-
33-
// Validate input - need either chainSelector or chainSelectorName
34-
if (!chainSelector && !chainSelectorName) {
35-
return undefined
36-
}
37-
38-
// If both chainFamily and network type are specified, use the most specific maps
39-
if (chainFamily && chainSelector !== undefined) {
40-
if (isTestnet === false) {
41-
return getBySelector(mainnetBySelectorByFamily[chainFamily])
42-
}
43-
44-
if (isTestnet === true) {
45-
return getBySelector(testnetBySelectorByFamily[chainFamily])
46-
}
47-
48-
// If user haven't defined if it's testnet or not we can try all networks, starting from testnet
49-
let network = getBySelector(testnetBySelectorByFamily[chainFamily])
50-
if (!network) {
51-
network = getBySelector(mainnetBySelectorByFamily[chainFamily])
52-
}
53-
return network
54-
}
55-
56-
if (chainFamily && chainSelectorName) {
57-
if (isTestnet === false) {
58-
return mainnetByNameByFamily[chainFamily].get(chainSelectorName)
59-
}
60-
61-
if (isTestnet === true) {
62-
return testnetByNameByFamily[chainFamily].get(chainSelectorName)
63-
}
64-
65-
// If user haven't defined if it's testnet or not we can try all networks, starting from testnet
66-
let network = testnetByNameByFamily[chainFamily].get(chainSelectorName)
67-
if (!network) {
68-
network = mainnetByNameByFamily[chainFamily].get(chainSelectorName)
69-
}
70-
return network
71-
}
72-
73-
// If only network type is specified, use the general maps
74-
if (chainSelector !== undefined) {
75-
if (isTestnet === false) {
76-
return getBySelector(mainnetBySelector)
77-
}
78-
79-
if (isTestnet === true) {
80-
return getBySelector(testnetBySelector)
81-
}
82-
83-
// If user haven't defined if it's testnet or not we can try all networks, starting from testnet
84-
let network = getBySelector(testnetBySelector)
85-
if (!network) {
86-
network = getBySelector(mainnetBySelector)
87-
}
88-
return network
89-
}
90-
91-
if (chainSelectorName) {
92-
if (isTestnet === false) {
93-
return mainnetByName.get(chainSelectorName)
94-
}
95-
96-
if (isTestnet === true) {
97-
return testnetByName.get(chainSelectorName)
98-
}
99-
100-
// If user haven't defined if it's testnet or not we can try all networks, starting from testnet
101-
let network = testnetByName.get(chainSelectorName)
102-
if (!network) {
103-
network = mainnetByName.get(chainSelectorName)
104-
}
105-
return network
106-
}
107-
108-
return undefined
109-
}
30+
export const getNetwork = (options: GetNetworkOptions): NetworkInfo | undefined =>
31+
defaultLookup.find(options)
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import type { ChainFamily, NetworkInfo } from './types'
2+
3+
export interface GetNetworkOptions {
4+
chainSelector?: bigint
5+
chainSelectorName?: string
6+
isTestnet?: boolean | undefined
7+
chainFamily?: ChainFamily
8+
}
9+
10+
export type NetworkMapBySelector = Map<bigint, NetworkInfo>
11+
export type NetworkMapByName = Map<string, NetworkInfo>
12+
export type NetworkFamilyMapBySelector = Record<ChainFamily, NetworkMapBySelector>
13+
export type NetworkFamilyMapByName = Record<ChainFamily, NetworkMapByName>
14+
15+
export interface NetworkMaps {
16+
mainnetByName: NetworkMapByName
17+
mainnetByNameByFamily: NetworkFamilyMapByName
18+
mainnetBySelector: NetworkMapBySelector
19+
mainnetBySelectorByFamily: NetworkFamilyMapBySelector
20+
testnetByName: NetworkMapByName
21+
testnetByNameByFamily: NetworkFamilyMapByName
22+
testnetBySelector: NetworkMapBySelector
23+
testnetBySelectorByFamily: NetworkFamilyMapBySelector
24+
}
25+
26+
export class NetworkLookup {
27+
constructor(private maps: NetworkMaps) {}
28+
29+
/**
30+
* High-performance network lookup using Maps for O(1) performance
31+
* @param options - Search criteria
32+
* @returns NetworkInfo if found, undefined otherwise
33+
*/
34+
find(options: GetNetworkOptions): NetworkInfo | undefined {
35+
const { chainSelector, chainSelectorName, isTestnet, chainFamily } = options
36+
37+
const getBySelector = (map: Map<bigint, NetworkInfo>) => {
38+
if (chainSelector === undefined) return undefined
39+
return map.get(chainSelector)
40+
}
41+
42+
// Validate input - need either chainSelector or chainSelectorName
43+
if (!chainSelector && !chainSelectorName) {
44+
return undefined
45+
}
46+
47+
// If both chainFamily and network type are specified, use the most specific maps
48+
if (chainFamily && chainSelector !== undefined) {
49+
if (isTestnet === false) {
50+
return getBySelector(this.maps.mainnetBySelectorByFamily[chainFamily])
51+
}
52+
53+
if (isTestnet === true) {
54+
return getBySelector(this.maps.testnetBySelectorByFamily[chainFamily])
55+
}
56+
57+
// If user haven't defined if it's testnet or not we can try all networks, starting from testnet
58+
let network = getBySelector(this.maps.testnetBySelectorByFamily[chainFamily])
59+
if (!network) {
60+
network = getBySelector(this.maps.mainnetBySelectorByFamily[chainFamily])
61+
}
62+
return network
63+
}
64+
65+
if (chainFamily && chainSelectorName) {
66+
if (isTestnet === false) {
67+
return this.maps.mainnetByNameByFamily[chainFamily].get(chainSelectorName)
68+
}
69+
70+
if (isTestnet === true) {
71+
return this.maps.testnetByNameByFamily[chainFamily].get(chainSelectorName)
72+
}
73+
74+
// If user haven't defined if it's testnet or not we can try all networks, starting from testnet
75+
let network = this.maps.testnetByNameByFamily[chainFamily].get(chainSelectorName)
76+
if (!network) {
77+
network = this.maps.mainnetByNameByFamily[chainFamily].get(chainSelectorName)
78+
}
79+
return network
80+
}
81+
82+
// If only network type is specified, use the general maps
83+
if (chainSelector !== undefined) {
84+
if (isTestnet === false) {
85+
return getBySelector(this.maps.mainnetBySelector)
86+
}
87+
88+
if (isTestnet === true) {
89+
return getBySelector(this.maps.testnetBySelector)
90+
}
91+
92+
// If user haven't defined if it's testnet or not we can try all networks, starting from testnet
93+
let network = getBySelector(this.maps.testnetBySelector)
94+
if (!network) {
95+
network = getBySelector(this.maps.mainnetBySelector)
96+
}
97+
return network
98+
}
99+
100+
if (chainSelectorName) {
101+
if (isTestnet === false) {
102+
return this.maps.mainnetByName.get(chainSelectorName)
103+
}
104+
105+
if (isTestnet === true) {
106+
return this.maps.testnetByName.get(chainSelectorName)
107+
}
108+
109+
// If user haven't defined if it's testnet or not we can try all networks, starting from testnet
110+
let network = this.maps.testnetByName.get(chainSelectorName)
111+
if (!network) {
112+
network = this.maps.mainnetByName.get(chainSelectorName)
113+
}
114+
return network
115+
}
116+
117+
return undefined
118+
}
119+
}

0 commit comments

Comments
 (0)