Skip to content

Commit 150b14d

Browse files
committed
Refactor getChainKey; add chain "slugs"
Slug is a piece to be used in urls. In our case `?chain=polygonAmoy` is gonna be `?chain=amoy`.
1 parent 0a2fc62 commit 150b14d

File tree

4 files changed

+106
-83
lines changed

4 files changed

+106
-83
lines changed

src/config/chains.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ name = "streamr-dev/dataunion"
2222
[polygonAmoy]
2323
dataUnionJoinServerUrl = "https://join.dataunions.org/"
2424
marketplaceChains = ['polygonAmoy']
25+
slug = 'amoy'
2526

2627
[[polygonAmoy.storageNodes]]
2728
name = "Streamr Germany"

src/utils/chainConfigExtension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const ChainConfigExtension = z.object({
3232
}),
3333
marketplaceChains: z.array(z.string()).optional().default([]),
3434
networkSubgraphUrl: z.string().optional(),
35+
slug: z.string().optional(),
3536
sponsorshipPaymentToken: z.string().optional().default('DATA'),
3637
storageNodes: z
3738
.array(

src/utils/chains.ts

Lines changed: 95 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Chain, config as configs } from '@streamr/config'
1+
import { Chain, ChainKey, config as configs } from '@streamr/config'
22
import { produce } from 'immer'
33
import { useMemo } from 'react'
44
import { useSearchParams } from 'react-router-dom'
@@ -11,24 +11,64 @@ import {
1111
} from '~/utils/chainConfigExtension'
1212
import formatConfigUrl from './formatConfigUrl'
1313

14-
function getPreferredChainName(chainName: string) {
15-
if (/amoy/i.test(chainName)) {
16-
return 'amoy'
14+
const lowerCasedChainKeyToChainKeyMap: Record<string, ChainKey | null | undefined> = {}
15+
16+
/**
17+
* @param candidate Chain key or chain slug (from config extension) or chain number. Defaults
18+
* to the default chain key (currently 'polygon').
19+
*/
20+
export function getChainKey(candidate: string | number): ChainKey {
21+
const key = typeof candidate === 'number' ? candidate : candidate.toLowerCase()
22+
23+
if (lowerCasedChainKeyToChainKeyMap[key] === null) {
24+
return defaultChainKey
1725
}
1826

19-
return chainName.toLowerCase()
20-
}
27+
if (lowerCasedChainKeyToChainKeyMap[key]) {
28+
return lowerCasedChainKeyToChainKeyMap[key]
29+
}
30+
31+
for (const chainKey in configs) {
32+
if (!isChainKey(chainKey)) {
33+
continue
34+
}
35+
36+
if (typeof key === 'number') {
37+
if (configs[chainKey].id === key) {
38+
lowerCasedChainKeyToChainKeyMap[key] = chainKey
2139

22-
function getChainConfigWithFallback(chainName: string): Chain {
23-
try {
24-
return getChainConfig(chainName)
25-
} catch (_) {}
40+
return chainKey
41+
}
42+
43+
continue
44+
}
45+
46+
if (chainKey.toLowerCase() === key) {
47+
lowerCasedChainKeyToChainKeyMap[key] = chainKey
48+
49+
return chainKey
50+
}
51+
52+
const slug = parsedChainConfigExtension[chainKey]?.slug?.toLowerCase()
53+
54+
if (key === slug) {
55+
lowerCasedChainKeyToChainKeyMap[key] = chainKey
56+
57+
return chainKey
58+
}
59+
}
2660

27-
return getChainConfig(defaultChainKey)
61+
console.warn(
62+
`Could not find a proper chain key for "${candidate}". Using default key (${defaultChainKey}).`,
63+
)
64+
65+
lowerCasedChainKeyToChainKeyMap[key] = null
66+
67+
return defaultChainKey
2868
}
2969

3070
export function getCurrentChain() {
31-
return getChainConfigWithFallback(
71+
return getChainConfig(
3272
new URLSearchParams(window.location.search).get('chain') || defaultChainKey,
3373
)
3474
}
@@ -40,7 +80,7 @@ export function getCurrentChainId() {
4080
export function useCurrentChain() {
4181
const chainName = useSearchParams()[0].get('chain') || defaultChainKey
4282

43-
return useMemo(() => getChainConfigWithFallback(chainName), [chainName])
83+
return useMemo(() => getChainConfig(chainName), [chainName])
4484
}
4585

4686
export function useCurrentChainId() {
@@ -61,95 +101,69 @@ export function useCurrentChainFullName() {
61101
interface ChainEntry {
62102
config: Chain
63103
configExtension: ChainConfigExtension
64-
chainKey: string
104+
chainKey: ChainKey
65105
}
66106

67-
const chainEntriesByIdOrName: Partial<Record<string | number, ChainEntry | null>> = {}
68-
69-
function getChainEntry(chainIdOrName: string | number) {
70-
const key =
71-
typeof chainIdOrName === 'string'
72-
? getPreferredChainName(chainIdOrName)
73-
: chainIdOrName
74-
75-
let entry = chainEntriesByIdOrName[key]
76-
77-
if (typeof entry === 'undefined') {
78-
entry = (() => {
79-
const source = Object.entries<Chain>(configs).find(([chainKey, config]) =>
80-
typeof chainIdOrName === 'string'
81-
? getPreferredChainName(chainIdOrName) ===
82-
getPreferredChainName(chainKey)
83-
: chainIdOrName === config.id,
84-
)
85-
86-
if (!source) {
87-
return null
88-
}
107+
const chainEntriesByIdOrName: Partial<Record<ChainKey, ChainEntry | null>> = {}
89108

90-
const [rawChainKey, config] = source
91-
92-
const chainKey = getPreferredChainName(rawChainKey)
93-
94-
const configExtension =
95-
parsedChainConfigExtension[chainKey] || fallbackChainConfigExtension
109+
function getChainEntry(chainKey: ChainKey): ChainEntry {
110+
if (chainEntriesByIdOrName[chainKey]) {
111+
return chainEntriesByIdOrName[chainKey]
112+
}
96113

97-
const { dockerHost } = configExtension
114+
const config: Chain = configs[chainKey]
98115

99-
const sanitizedConfig = produce(config, (draft) => {
100-
draft.name = ethereumNetworks[config.id] || config.name
116+
const configExtension =
117+
parsedChainConfigExtension[chainKey] || fallbackChainConfigExtension
101118

102-
for (const rpc of draft.rpcEndpoints) {
103-
rpc.url = formatConfigUrl(rpc.url, {
104-
dockerHost,
105-
})
106-
}
119+
const { dockerHost } = configExtension
107120

108-
if (draft.entryPoints) {
109-
for (const entrypoint of draft.entryPoints) {
110-
entrypoint.websocket.host = formatConfigUrl(
111-
entrypoint.websocket.host,
112-
{
113-
dockerHost,
114-
},
115-
)
116-
}
117-
}
121+
const sanitizedConfig = produce(config, (draft) => {
122+
draft.name = ethereumNetworks[config.id] || config.name
118123

119-
if (draft.theGraphUrl) {
120-
draft.theGraphUrl = formatConfigUrl(draft.theGraphUrl, { dockerHost })
121-
}
124+
for (const rpc of draft.rpcEndpoints) {
125+
rpc.url = formatConfigUrl(rpc.url, {
126+
dockerHost,
122127
})
128+
}
123129

124-
return {
125-
chainKey,
126-
config: sanitizedConfig,
127-
configExtension,
130+
if (draft.entryPoints) {
131+
for (const entrypoint of draft.entryPoints) {
132+
entrypoint.websocket.host = formatConfigUrl(entrypoint.websocket.host, {
133+
dockerHost,
134+
})
128135
}
129-
})()
136+
}
130137

131-
chainEntriesByIdOrName[key] = entry
132-
}
138+
if (draft.theGraphUrl) {
139+
draft.theGraphUrl = formatConfigUrl(draft.theGraphUrl, { dockerHost })
140+
}
141+
})
133142

134-
if (!entry) {
135-
throw new Error(
136-
`Could not find config for "${chainIdOrName}" (${
137-
typeof chainIdOrName === 'string' ? 'chain name' : 'chain id'
138-
})`,
139-
)
143+
const entry: ChainEntry = {
144+
chainKey,
145+
config: sanitizedConfig,
146+
configExtension,
140147
}
141148

149+
chainEntriesByIdOrName[chainKey] = entry
150+
142151
return entry
143152
}
144153

145154
export function getChainConfig(chainIdOrChainKey: string | number): Chain {
146-
return getChainEntry(chainIdOrChainKey).config
155+
return getChainEntry(getChainKey(chainIdOrChainKey)).config
147156
}
148157

149-
export function getChainKey(chainId: number) {
150-
return getChainEntry(chainId).chainKey
158+
export function getChainConfigExtension(chainId: number): ChainConfigExtension {
159+
return getChainEntry(getChainKey(chainId)).configExtension
151160
}
152161

153-
export function getChainConfigExtension(chainId: number) {
154-
return getChainEntry(chainId).configExtension
162+
/**
163+
* Checks if a given string is a `ChainKey`.
164+
* @param candidate Any string.
165+
* @returns `true` if the given string is config's own key.
166+
*/
167+
function isChainKey(candidate: string): candidate is ChainKey {
168+
return Object.prototype.hasOwnProperty.call(configs, candidate)
155169
}

src/utils/routes.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { ChainKey } from '@streamr/config'
12
import queryString from 'query-string'
23
import { defaultChainKey } from '~/consts'
4+
import { parsedChainConfigExtension } from '~/utils/chainConfigExtension'
35
import { getChainKey } from './chains'
46

57
interface RouteOptions {
@@ -8,14 +10,19 @@ interface RouteOptions {
810
}
911

1012
export function routeOptions(
11-
chain: string | number,
13+
chainIdOrChainKey: ChainKey | number,
1214
search: Record<string, any> = {},
1315
hash = '',
1416
): RouteOptions {
17+
const chain =
18+
typeof chainIdOrChainKey === 'number'
19+
? getChainKey(chainIdOrChainKey)
20+
: parsedChainConfigExtension[chainIdOrChainKey]?.slug || chainIdOrChainKey
21+
1522
return {
1623
search: {
1724
...search,
18-
chain: typeof chain === 'string' ? chain : getChainKey(chain),
25+
chain,
1926
},
2027
hash,
2128
}

0 commit comments

Comments
 (0)