Skip to content

Commit 780ebd3

Browse files
authored
Merge pull request #1976 from streamr-dev/amoy-to-polygonAmoy
Add chain "slug"; use proper chain key for Polygon Amoy (in local configs)
2 parents 6f62962 + 9405443 commit 780ebd3

File tree

6 files changed

+119
-96
lines changed

6 files changed

+119
-96
lines changed

src/components/ChainSelector.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import UnstyledNetworkIcon from '~/shared/components/NetworkIcon'
99
import SvgIcon from '~/shared/components/SvgIcon'
1010
import { COLORS, LAPTOP } from '~/shared/utils/styled'
1111
import { StreamDraft } from '~/stores/streamDraft'
12-
import { getChainKey, useCurrentChain } from '~/utils/chains'
12+
import { getChainSlug, useCurrentChain } from '~/utils/chains'
1313

1414
type MenuItemProps = {
1515
chain: Chain
@@ -45,14 +45,14 @@ const Menu = ({ chains, selectedChain, toggle }: MenuProps) => {
4545
onClick={() => {
4646
toggle(false)
4747

48-
const chainKey = getChainKey(c.id)
48+
const slug = getChainSlug(c.id)
4949

5050
setSearchParams((prev) => {
5151
const { chain: _, ...rest } = Object.fromEntries(prev)
5252

53-
return chainKey === defaultChainKey
53+
return slug === getChainSlug(defaultChainKey)
5454
? rest
55-
: { ...rest, chain: chainKey }
55+
: { ...rest, chain: slug }
5656
})
5757
}}
5858
/>

src/config/chains.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ address = "0xde1112f631486CfC759A50196853011528bC5FA0"
1919
chainId = 31337
2020
name = "streamr-dev/dataunion"
2121

22-
[amoy]
22+
[polygonAmoy]
2323
dataUnionJoinServerUrl = "https://join.dataunions.org/"
24-
marketplaceChains = ['amoy']
24+
marketplaceChains = ['polygonAmoy']
25+
slug = 'amoy'
2526

26-
[[amoy.storageNodes]]
27+
[[polygonAmoy.storageNodes]]
2728
name = "Streamr Germany"
2829
address = "0x31546eEA76F2B2b3C5cC06B1c93601dc35c9D916"
2930

30-
[[amoy.dataunionGraphNames]]
31+
[[polygonAmoy.dataunionGraphNames]]
3132
chainId = 80002
3233
name = "samt1803/dataunion-subgraphs"
3334

src/config/environments.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
[development]
2-
availableChains = ['dev2', 'polygon', 'amoy']
2+
availableChains = ['dev2', 'polygon', 'polygonAmoy']
33
platformOriginUrl = ""
44
streamrUrl = ""
55

6-
[amoy]
7-
availableChains = ['amoy', 'polygon']
6+
[polygonAmoy]
7+
availableChains = ['polygonAmoy', 'polygon']
88
platformOriginUrl = "https://staging.streamr.network"
99
streamrUrl = "https://staging.streamr.network"
1010

1111
[production]
12-
availableChains = ['polygon', 'amoy']
12+
availableChains = ['polygon', 'polygonAmoy']

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: 101 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
39+
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+
}
2160

22-
function getChainConfigWithFallback(chainName: string): Chain {
23-
try {
24-
return getChainConfig(chainName)
25-
} catch (_) {}
61+
console.warn(
62+
`Could not find a proper chain key for "${candidate}". Using default key (${defaultChainKey}).`,
63+
)
64+
65+
lowerCasedChainKeyToChainKeyMap[key] = null
2666

27-
return getChainConfig(defaultChainKey)
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,75 @@ 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-
}
89-
90-
const [rawChainKey, config] = source
91-
92-
const chainKey = getPreferredChainName(rawChainKey)
107+
const chainKeyToChainEntryMap: Partial<Record<ChainKey, ChainEntry | null>> = {}
93108

94-
const configExtension =
95-
parsedChainConfigExtension[chainKey] || fallbackChainConfigExtension
109+
function getChainEntry(chainKey: ChainKey): ChainEntry {
110+
if (chainKeyToChainEntryMap[chainKey]) {
111+
return chainKeyToChainEntryMap[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+
chainKeyToChainEntryMap[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
156+
}
157+
158+
export function getChainConfigExtension(chainId: number): ChainConfigExtension {
159+
return getChainEntry(getChainKey(chainId)).configExtension
147160
}
148161

149-
export function getChainKey(chainId: number) {
150-
return getChainEntry(chainId).chainKey
162+
export function getChainSlug(chainIdOrChainKey: ChainKey | number): string {
163+
const chainEntry = getChainEntry(getChainKey(chainIdOrChainKey))
164+
165+
return chainEntry.configExtension.slug || chainEntry.chainKey
151166
}
152167

153-
export function getChainConfigExtension(chainId: number) {
154-
return getChainEntry(chainId).configExtension
168+
/**
169+
* Checks if a given string is a `ChainKey`.
170+
* @param candidate Any string.
171+
* @returns `true` if the given string is config's own key.
172+
*/
173+
function isChainKey(candidate: string): candidate is ChainKey {
174+
return Object.prototype.hasOwnProperty.call(configs, candidate)
155175
}

src/utils/routes.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1+
import { ChainKey } from '@streamr/config'
12
import queryString from 'query-string'
23
import { defaultChainKey } from '~/consts'
3-
import { getChainKey } from './chains'
4+
import { getChainSlug } from './chains'
45

56
interface RouteOptions {
67
search?: Record<'chain', string> & Record<string, any>
78
hash?: string
89
}
910

1011
export function routeOptions(
11-
chain: string | number,
12+
chainIdOrChainKey: ChainKey | number,
1213
search: Record<string, any> = {},
1314
hash = '',
1415
): RouteOptions {
1516
return {
1617
search: {
1718
...search,
18-
chain: typeof chain === 'string' ? chain : getChainKey(chain),
19+
chain: getChainSlug(chainIdOrChainKey),
1920
},
2021
hash,
2122
}

0 commit comments

Comments
 (0)