@snowbridge/registry 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.turbo/turbo-build.log +1 -2
  2. package/dist/index.d.ts +6 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +24 -2
  5. package/dist/paseo_sepolia_bridge_info.g.d.ts +330 -0
  6. package/dist/paseo_sepolia_bridge_info.g.d.ts.map +1 -0
  7. package/dist/paseo_sepolia_bridge_info.g.js +350 -0
  8. package/dist/polkadot_mainnet_bridge_info.g.d.ts +1983 -0
  9. package/dist/polkadot_mainnet_bridge_info.g.d.ts.map +1 -0
  10. package/dist/polkadot_mainnet_bridge_info.g.js +2264 -0
  11. package/dist/transfers.d.ts +3 -8
  12. package/dist/transfers.d.ts.map +1 -1
  13. package/dist/transfers.js +54 -215
  14. package/dist/westend_sepolia_bridge_info.g.d.ts +344 -0
  15. package/dist/westend_sepolia_bridge_info.g.d.ts.map +1 -0
  16. package/dist/westend_sepolia_bridge_info.g.js +376 -0
  17. package/package.json +7 -7
  18. package/scripts/buildRegistry.ts +466 -29
  19. package/src/index.ts +24 -2
  20. package/src/paseo_sepolia_bridge_info.g.ts +349 -0
  21. package/src/polkadot_mainnet_bridge_info.g.ts +2287 -0
  22. package/src/transfers.ts +58 -266
  23. package/src/westend_sepolia_bridge_info.g.ts +384 -0
  24. package/dist/environment.d.ts +0 -3
  25. package/dist/environment.d.ts.map +0 -1
  26. package/dist/environment.js +0 -181
  27. package/dist/local_e2e.registry.json +0 -391
  28. package/dist/paseo_sepolia.registry.json +0 -231
  29. package/dist/polkadot_mainnet.registry.json +0 -1805
  30. package/dist/registry.d.ts +0 -3
  31. package/dist/registry.d.ts.map +0 -1
  32. package/dist/registry.js +0 -61
  33. package/dist/westend_sepolia.registry.json +0 -283
  34. package/src/environment.ts +0 -185
  35. package/src/local_e2e.registry.json +0 -391
  36. package/src/paseo_sepolia.registry.json +0 -231
  37. package/src/polkadot_mainnet.registry.json +0 -1805
  38. package/src/registry.ts +0 -63
  39. package/src/westend_sepolia.registry.json +0 -283
@@ -16,15 +16,399 @@ import {
16
16
  PrecompileMap,
17
17
  XC20TokenMap,
18
18
  XcmVersion,
19
+ BridgeInfo,
20
+ TransferRoute,
21
+ ChainId,
22
+ ChainKey,
23
+ ParachainKind,
19
24
  } from "@snowbridge/base-types"
20
25
  import { ApiPromise, HttpProvider, WsProvider } from "@polkadot/api"
21
26
  import { isFunction } from "@polkadot/util"
22
27
  import { writeFile } from "fs/promises"
23
- import { environmentFor } from "../src"
24
28
  import { AbstractProvider, Contract, ethers } from "ethers"
25
29
  import { IGatewayV1__factory as IGateway__factory } from "@snowbridge/contract-types"
26
30
  import { parachains as ParaImpl, xcmBuilder, assetsV2 } from "@snowbridge/api"
27
31
 
32
+ export type Path = {
33
+ source: ChainId
34
+ destination: ChainId
35
+ asset: string
36
+ }
37
+
38
+ const SNOWBRIDGE_ENV: { [env: string]: Environment } = {
39
+ local_e2e: {
40
+ name: "local_e2e",
41
+ ethChainId: 11155111,
42
+ beaconApiUrl: "http://127.0.0.1:9596",
43
+ ethereumChains: {
44
+ "11155111": "ws://127.0.0.1:8546",
45
+ },
46
+ relaychainUrl: "ws://127.0.0.1:9944",
47
+ parachains: {
48
+ "1000": "ws://127.0.0.1:12144",
49
+ "1002": "ws://127.0.0.1:11144",
50
+ "2000": "ws://127.0.0.1:13144",
51
+ },
52
+ gatewayContract: "0xb1185ede04202fe62d38f5db72f71e38ff3e8305",
53
+ beefyContract: "0x83428c7db9815f482a39a1715684dcf755021997",
54
+ assetHubParaId: 1000,
55
+ bridgeHubParaId: 1002,
56
+ v2_parachains: [1000],
57
+ indexerGraphQlUrl: "http://127.0.0.1/does/not/exist",
58
+ },
59
+ paseo_sepolia: {
60
+ name: "paseo_sepolia",
61
+ ethChainId: 11155111,
62
+ beaconApiUrl: "https://lodestar-sepolia.chainsafe.io",
63
+ ethereumChains: {
64
+ "11155111": "https://ethereum-sepolia-rpc.publicnode.com",
65
+ },
66
+ relaychainUrl: "wss://paseo-rpc.n.dwellir.com",
67
+ parachains: {
68
+ "1000": "wss://asset-hub-paseo-rpc.n.dwellir.com",
69
+ "1002": "wss://bridge-hub-paseo.dotters.network",
70
+ "3369": "wss://paseo-muse-rpc.polkadot.io",
71
+ "2043": `wss://parachain-testnet-rpc.origin-trail.network`,
72
+ },
73
+ gatewayContract: "0x1607C1368bc943130258318c91bBd8cFf3D063E6",
74
+ beefyContract: "0x2c780945beb1241fE9c645800110cb9C4bBbb639",
75
+ assetHubParaId: 1000,
76
+ bridgeHubParaId: 1002,
77
+ v2_parachains: [1000],
78
+ indexerGraphQlUrl:
79
+ "https://snowbridge.squids.live/snowbridge-subsquid-paseo@v1/api/graphql",
80
+ metadataOverrides: {
81
+ // Change the name of TRAC
82
+ "0xef32abea56beff54f61da319a7311098d6fbcea9": {
83
+ name: "OriginTrail TRAC",
84
+ symbol: "TRAC",
85
+ },
86
+ },
87
+ },
88
+ polkadot_mainnet: {
89
+ name: "polkadot_mainnet",
90
+ ethChainId: 1,
91
+ beaconApiUrl: "https://lodestar-mainnet.chainsafe.io",
92
+ ethereumChains: {
93
+ "1": "https://ethereum-rpc.publicnode.com",
94
+ "1284": "https://rpc.api.moonbeam.network",
95
+ "8453": "https://base-rpc.publicnode.com",
96
+ },
97
+ relaychainUrl: "https://polkadot-rpc.n.dwellir.com",
98
+ parachains: {
99
+ "1000": "wss://asset-hub-polkadot-rpc.n.dwellir.com",
100
+ "1002": "https://bridge-hub-polkadot-rpc.n.dwellir.com",
101
+ "3369": "wss://polkadot-mythos-rpc.polkadot.io",
102
+ "2034": "wss://hydration-rpc.n.dwellir.com",
103
+ "2030": "wss://bifrost-polkadot.ibp.network",
104
+ "2004": "wss://moonbeam.ibp.network",
105
+ "2000": "wss://acala-rpc-0.aca-api.network",
106
+ "2043": "wss://parachain-rpc.origin-trail.network",
107
+ // TODO: Add back in jampton once we have an indexer in place.
108
+ //"3397": "wss://rpc.jamton.network",
109
+ },
110
+ gatewayContract: "0x27ca963c279c93801941e1eb8799c23f407d68e7",
111
+ beefyContract: "0x1817874feAb3ce053d0F40AbC23870DB35C2AFfc",
112
+ assetHubParaId: 1000,
113
+ bridgeHubParaId: 1002,
114
+ v2_parachains: [1000],
115
+ indexerGraphQlUrl:
116
+ "https://snowbridge.squids.live/snowbridge-subsquid-polkadot@v2/api/graphql",
117
+ kusama: {
118
+ assetHubParaId: 1000,
119
+ bridgeHubParaId: 1002,
120
+ parachains: {
121
+ "1000": "wss://asset-hub-kusama-rpc.n.dwellir.com",
122
+ "1002": "https://bridge-hub-kusama-rpc.n.dwellir.com",
123
+ },
124
+ },
125
+ precompiles: {
126
+ // Add override for mythos token and add precompile for moonbeam
127
+ "2004": "0x000000000000000000000000000000000000081a",
128
+ },
129
+ metadataOverrides: {
130
+ // Change the name of TRAC
131
+ "0xaa7a9ca87d3694b5755f213b5d04094b8d0f0a6f": {
132
+ name: "OriginTrail TRAC",
133
+ },
134
+ },
135
+ l2Bridge: {
136
+ acrossAPIUrl: "https://app.across.to/api",
137
+ l1AdapterAddress: "0x313E8c9Fb47613f2B1A436bE978c2BB75727fcC5",
138
+ l1HandlerAddress: "0x924a9f036260DdD5808007E1AA95f08eD08aA569",
139
+ l1FeeTokenAddress: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
140
+ l1SwapQuoterAddress: "0x61fFE014bA17989E743c5F6cB21bF9697530B21e",
141
+ l1SwapRouterAddress: "0xE592427A0AEce92De3Edee1F18E0157C05861564",
142
+ l2Chains: {
143
+ "8453": {
144
+ adapterAddress: "0xCd5d2c665E3AC84bF5c67FE7a0C48748dA40db2F",
145
+ feeTokenAddress: "0x4200000000000000000000000000000000000006",
146
+ swapRoutes: [
147
+ // WETH
148
+ {
149
+ inputToken: "0x4200000000000000000000000000000000000006",
150
+ outputToken: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
151
+ swapFee: 0,
152
+ },
153
+ // USDC
154
+ {
155
+ inputToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
156
+ outputToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
157
+ swapFee: 500,
158
+ },
159
+ ],
160
+ },
161
+ },
162
+ },
163
+ },
164
+ westend_sepolia: {
165
+ name: "westend_sepolia",
166
+ ethChainId: 11155111,
167
+ beaconApiUrl: "https://lodestar-sepolia.chainsafe.io",
168
+ ethereumChains: {
169
+ "11155111": "https://ethereum-sepolia-rpc.publicnode.com",
170
+ "84532": "https://base-sepolia-rpc.publicnode.com",
171
+ },
172
+ relaychainUrl: "wss://westend-rpc.n.dwellir.com",
173
+ parachains: {
174
+ "1000": "wss://asset-hub-westend-rpc.n.dwellir.com",
175
+ "1002": "wss://bridge-hub-westend-rpc.n.dwellir.com",
176
+ },
177
+ gatewayContract: "0x9ed8b47bc3417e3bd0507adc06e56e2fa360a4e9",
178
+ beefyContract: "0xA04460B1D8bBef33F54edB2C3115e3E4D41237A6",
179
+ assetHubParaId: 1000,
180
+ bridgeHubParaId: 1002,
181
+ v2_parachains: [1000],
182
+ indexerGraphQlUrl:
183
+ "https://snowbridge.squids.live/snowbridge-subsquid-westend@v1/api/graphql",
184
+ l2Bridge: {
185
+ acrossAPIUrl: "https://testnet.across.to/api",
186
+ l1AdapterAddress: "0xA5B8589bD534701be49916c4d2e634aB1c765Cbf",
187
+ l1HandlerAddress: "0x924a9f036260DdD5808007E1AA95f08eD08aA569",
188
+ l1FeeTokenAddress: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14",
189
+ l1SwapRouterAddress: "0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E",
190
+ l1SwapQuoterAddress: "0xEd1f6473345F45b75F8179591dd5bA1888cf2FB3",
191
+ l2Chains: {
192
+ "84532": {
193
+ adapterAddress: "0xf06939613A3838Af11104c898758220dB9093679",
194
+ feeTokenAddress: "0x4200000000000000000000000000000000000006",
195
+ swapRoutes: [
196
+ // WETH
197
+ {
198
+ inputToken: "0x4200000000000000000000000000000000000006",
199
+ outputToken: "0xfff9976782d46cc05630d1f6ebab18b2324d6b14",
200
+ swapFee: 0,
201
+ },
202
+ // USDC
203
+ {
204
+ inputToken: "0x036cbd53842c5426634e7929541ec2318f3dcf7e",
205
+ outputToken: "0x1c7d4b196cb0c7b01d743fbc6116a902379c7238",
206
+ swapFee: 500,
207
+ },
208
+ ],
209
+ },
210
+ },
211
+ },
212
+ },
213
+ }
214
+
215
+ export function defaultPathFilter(envName: string): (_: Path) => boolean {
216
+ switch (envName) {
217
+ case "westend_sepolia": {
218
+ return (path: Path) => {
219
+ // Frequency
220
+ if (path.asset === "0x72c610e05eaafcdf1fa7a2da15374ee90edb1620") {
221
+ return false
222
+ }
223
+ // Disable para to para transfers
224
+ if (path.source.kind === "polkadot" && path.destination.kind === "polkadot") {
225
+ return false
226
+ }
227
+ return true
228
+ }
229
+ }
230
+ case "paseo_sepolia":
231
+ return (path: Path) => {
232
+ // Disallow MUSE to any location but 3369
233
+ if (
234
+ path.asset === "0xb34a6924a02100ba6ef12af1c798285e8f7a16ee" &&
235
+ ((path.destination.id !== 3369 && path.source.kind === "ethereum") ||
236
+ (path.source.id !== 3369 && path.source.kind === "polkadot"))
237
+ ) {
238
+ return false
239
+ }
240
+ // Disable para to para transfers
241
+ if (path.source.kind === "polkadot" && path.destination.kind === "polkadot") {
242
+ return false
243
+ }
244
+ return true
245
+ }
246
+ case "polkadot_mainnet":
247
+ return (path: Path) => {
248
+ // Disallow MYTH to any location but 3369
249
+ if (
250
+ path.asset === "0xba41ddf06b7ffd89d1267b5a93bfef2424eb2003" &&
251
+ ((path.destination.id !== 3369 && path.source.kind === "ethereum") ||
252
+ (path.source.id !== 3369 && path.source.kind === "polkadot"))
253
+ ) {
254
+ return false
255
+ }
256
+
257
+ // Allow TRAC to go to Hydration (2034) and Neuroweb (2043) only
258
+ if (
259
+ path.asset === "0xaa7a9ca87d3694b5755f213b5d04094b8d0f0a6f" &&
260
+ ((path.destination.id !== 2034 &&
261
+ path.destination.id !== 2043 &&
262
+ path.source.kind === "ethereum") ||
263
+ (path.source.id !== 2034 &&
264
+ path.source.id !== 2043 &&
265
+ path.source.kind === "polkadot"))
266
+ ) {
267
+ return false
268
+ }
269
+
270
+ // Disable stable coins in the UI from Ethereum to Polkadot
271
+ if (
272
+ (path.asset === "0x9d39a5de30e57443bff2a8307a4256c8797a3497" || // Staked USDe
273
+ path.asset === "0xa3931d71877c0e7a3148cb7eb4463524fec27fbd" || // Savings USD
274
+ path.asset === "0x6b175474e89094c44da98b954eedeac495271d0f") && // DAI
275
+ path.destination.id === 2034 // Hydration
276
+ ) {
277
+ return false
278
+ }
279
+ // Disable para to para transfers except for hydration
280
+ if (
281
+ path.source.kind === "polkadot" &&
282
+ path.destination.kind === "polkadot" &&
283
+ !(
284
+ (path.source.id === 2034 && path.destination.id == 1000) ||
285
+ (path.source.id === 1000 && path.destination.id === 2034)
286
+ )
287
+ ) {
288
+ return false
289
+ }
290
+ return true
291
+ }
292
+
293
+ default:
294
+ return (_: Path) => true
295
+ }
296
+ }
297
+
298
+ function buildTransferLocations(
299
+ registry: AssetRegistry,
300
+ filter?: (path: Path) => boolean,
301
+ ): TransferRoute[] {
302
+ const ethChain = registry.ethereumChains[`ethereum_${registry.ethChainId}`]
303
+ const parachains = Object.values(registry.parachains).filter(
304
+ (p) => !(p.kind === "polkadot" && p.id === registry.bridgeHubParaId),
305
+ )
306
+
307
+ const pathFilter = filter ?? defaultPathFilter(registry.environment)
308
+
309
+ const locations: Path[] = []
310
+
311
+ const ethAssets = Object.keys(ethChain.assets)
312
+ // Bridged paths
313
+ for (const parachain of parachains) {
314
+ const destinationAssets = Object.keys(parachain.assets)
315
+ const commonAssets = new Set(
316
+ ethAssets.filter((sa) => destinationAssets.find((da) => da === sa)),
317
+ )
318
+ for (const asset of commonAssets) {
319
+ const p1: Path = {
320
+ source: { kind: ethChain.kind, id: ethChain.id },
321
+ destination: { kind: parachain.kind, id: parachain.id },
322
+ asset,
323
+ }
324
+ if (pathFilter(p1)) {
325
+ locations.push(p1)
326
+ }
327
+ const p2: Path = {
328
+ source: p1.destination,
329
+ destination: p1.source,
330
+ asset,
331
+ }
332
+ if (pathFilter(p2)) {
333
+ locations.push(p2)
334
+ }
335
+ if (
336
+ parachain.info.evmChainId &&
337
+ registry.ethereumChains[`ethereum_${parachain.info.evmChainId}`]
338
+ ) {
339
+ const p3: Path = {
340
+ source: {
341
+ kind: "ethereum",
342
+ id: parachain.info.evmChainId,
343
+ },
344
+ destination: p1.source, // Ethereum
345
+ asset,
346
+ }
347
+ if (pathFilter(p3)) {
348
+ locations.push(p3)
349
+ }
350
+ }
351
+ }
352
+ }
353
+
354
+ // Local paths
355
+ const assetHub = registry.parachains[`polkadot_${registry.assetHubParaId}`]
356
+ for (const parachain of parachains) {
357
+ if (parachain.kind === assetHub.kind && parachain.id === assetHub.id) continue
358
+ const assetHubAssets = Object.keys(assetHub.assets)
359
+ const destinationAssets = Object.keys(parachain.assets)
360
+
361
+ // The asset exists on ethereum, parachain and asset hub
362
+ const commonAssets = new Set(
363
+ ethAssets.filter(
364
+ (sa) =>
365
+ assetHubAssets.find((da) => da === sa) &&
366
+ destinationAssets.find((da) => da === sa),
367
+ ),
368
+ )
369
+ for (const asset of commonAssets) {
370
+ const p1: Path = {
371
+ source: { kind: assetHub.kind, id: assetHub.id },
372
+ destination: { kind: parachain.kind, id: parachain.id },
373
+ asset,
374
+ }
375
+ if (pathFilter(p1)) {
376
+ locations.push(p1)
377
+ }
378
+ const p2: Path = {
379
+ source: p1.destination, // Parachain
380
+ destination: p1.source, // Asset Hub
381
+ asset,
382
+ }
383
+ if (pathFilter(p2)) {
384
+ locations.push(p2)
385
+ }
386
+ }
387
+ }
388
+
389
+ const results: TransferRoute[] = []
390
+ for (const location of locations) {
391
+ let source = results.find(
392
+ (s) =>
393
+ s.from.kind === location.source.kind &&
394
+ s.from.id === location.source.id &&
395
+ s.to.kind === location.destination.kind &&
396
+ s.to.id === location.destination.id,
397
+ )
398
+
399
+ if (!source) {
400
+ source = {
401
+ from: location.source,
402
+ to: location.destination,
403
+ assets: [],
404
+ }
405
+ results.push(source)
406
+ }
407
+ source.assets = source.assets.concat(location.asset)
408
+ }
409
+ return results
410
+ }
411
+
28
412
  async function buildRegistry(environment: Environment): Promise<AssetRegistry> {
29
413
  const {
30
414
  relaychainUrl,
@@ -139,6 +523,7 @@ async function buildRegistry(environment: Environment): Promise<AssetRegistry> {
139
523
  const para = await indexParachain(
140
524
  accessor,
141
525
  providers[assetHubParaId.toString()].accessor,
526
+ "polkadot",
142
527
  ethChainId,
143
528
  parachainId,
144
529
  assetHubParaId,
@@ -149,7 +534,7 @@ async function buildRegistry(environment: Environment): Promise<AssetRegistry> {
149
534
  return { parachainId, para }
150
535
  }),
151
536
  )) {
152
- paras[parachainId.toString()] = para
537
+ paras[`polkadot_${parachainId}`] = para
153
538
  }
154
539
 
155
540
  // Index Ethereum chain
@@ -170,7 +555,7 @@ async function buildRegistry(environment: Environment): Promise<AssetRegistry> {
170
555
  )
171
556
  }),
172
557
  )) {
173
- ethChains[ethChainInfo.chainId.toString()] = ethChainInfo
558
+ ethChains[ethChainInfo.key] = ethChainInfo
174
559
  }
175
560
 
176
561
  let kusamaConfig: KusamaConfig | undefined
@@ -187,6 +572,7 @@ async function buildRegistry(environment: Environment): Promise<AssetRegistry> {
187
572
  const para = await indexParachain(
188
573
  accessor,
189
574
  providers[assetHubParaId].accessor,
575
+ "kusama",
190
576
  ethChainId,
191
577
  accessor.parachainId,
192
578
  assetHubParaId,
@@ -195,7 +581,7 @@ async function buildRegistry(environment: Environment): Promise<AssetRegistry> {
195
581
  )
196
582
 
197
583
  const kusamaParas: ParachainMap = {}
198
- kusamaParas[para.parachainId] = para
584
+ kusamaParas[para.key] = para
199
585
 
200
586
  kusamaConfig = {
201
587
  parachains: kusamaParas,
@@ -304,12 +690,13 @@ async function checkSnowbridgeV2Support(
304
690
  async function indexParachain(
305
691
  parachain: ParaImpl.ParachainBase,
306
692
  assetHub: ParaImpl.ParachainBase,
693
+ kind: ParachainKind,
307
694
  ethChainId: number,
308
695
  parachainId: number,
309
696
  assetHubParaId: number,
310
697
  pnaAssets: PNAMap,
311
698
  assetOverrides: AssetOverrideMap,
312
- v2_parachains?: number[],
699
+ v2_parachains?: readonly number[],
313
700
  ): Promise<Parachain> {
314
701
  const info = await parachain.chainProperties()
315
702
 
@@ -386,7 +773,9 @@ async function indexParachain(
386
773
  )
387
774
  }
388
775
  return {
389
- parachainId,
776
+ id: parachainId,
777
+ kind,
778
+ key: `${kind}_${parachainId}`,
390
779
  features: {
391
780
  hasPalletXcm,
392
781
  hasDryRunApi,
@@ -422,7 +811,7 @@ async function indexEthChain(
422
811
  const id = networkName !== "unknown" ? networkName : undefined
423
812
  if (networkChainId == ethChainId) {
424
813
  // Asset Hub and get meta data
425
- const assetHub = parachains[assetHubParaId.toString()]
814
+ const assetHub = parachains[`polkadot_${assetHubParaId}`]
426
815
  const gateway = IGateway__factory.connect(gatewayAddress, provider)
427
816
 
428
817
  const assets: ERC20MetadataMap = {}
@@ -475,9 +864,10 @@ async function indexEthChain(
475
864
  )
476
865
  }
477
866
  return {
478
- chainId: networkChainId,
867
+ kind: "ethereum",
868
+ id: networkChainId,
479
869
  assets,
480
- id: id ?? `chain_${networkChainId}`,
870
+ key: `ethereum_${networkChainId}`,
481
871
  baseDeliveryGas: 120_000n,
482
872
  }
483
873
  } else if (networkChainId in l2Chains) {
@@ -499,14 +889,15 @@ async function indexEthChain(
499
889
  swapFee: 0,
500
890
  }
501
891
  return {
502
- chainId: networkChainId,
892
+ kind: "ethereum_l2",
893
+ id: networkChainId,
503
894
  assets,
504
- id: id ?? `l2_${networkChainId}`,
895
+ key: `ethereum_l2_${networkChainId}`,
505
896
  }
506
897
  } else {
507
898
  let evmParachainChain: Parachain | undefined
508
899
  for (const paraId in parachains) {
509
- const parachain = parachains[paraId]
900
+ const parachain = parachains[paraId as ChainKey<"polkadot">]
510
901
  if (parachain.info.evmChainId === networkChainId) {
511
902
  evmParachainChain = parachain
512
903
  break
@@ -526,7 +917,7 @@ async function indexEthChain(
526
917
  xcTokenMap[token] = xc20
527
918
  assets[xc20] = asset
528
919
  }
529
- const paraId = evmParachainChain.parachainId.toString()
920
+ const paraId = evmParachainChain.id.toString()
530
921
  if (!(paraId in precompiles)) {
531
922
  throw Error(
532
923
  `No precompile configured for parachain ${paraId} (ethereum chain ${networkChainId}).`,
@@ -548,13 +939,14 @@ async function indexEthChain(
548
939
  assets[evmParachainChain.xcDOT] = xc20DOTAsset
549
940
 
550
941
  return {
551
- chainId: networkChainId,
552
- evmParachainId: evmParachainChain.parachainId,
942
+ kind: "ethereum",
943
+ id: networkChainId,
944
+ key: `ethereum_${networkChainId}`,
945
+ evmParachainId: evmParachainChain.id,
553
946
  assets,
554
947
  precompile,
555
948
  xcDOT: evmParachainChain.xcDOT,
556
949
  xcTokenMap,
557
- id: id ?? `evm_${evmParachainChain.info.specName}`,
558
950
  }
559
951
  }
560
952
  }
@@ -652,18 +1044,63 @@ async function getRegisteredPnas(
652
1044
  if (process.env.NODE_ENV !== undefined) {
653
1045
  env = process.env.NODE_ENV
654
1046
  }
655
- const registry = await buildRegistry(environmentFor(env))
656
- const json = JSON.stringify(
657
- registry,
658
- (key, value) => {
659
- if (typeof value === "bigint") {
660
- return `bigint:${value.toString()}`
1047
+ if (!(env in SNOWBRIDGE_ENV)) {
1048
+ throw Error(`Unknown environment ${env}.`)
1049
+ }
1050
+ const environment = SNOWBRIDGE_ENV[env]
1051
+ const registry = await buildRegistry(environment)
1052
+ const routes = buildTransferLocations(registry)
1053
+ const bridge: BridgeInfo = { environment, routes, registry }
1054
+ const json = generateTsObject(bridge, 4)
1055
+ const fileContents = `const registry = ${json} as const\nexport default registry\n`
1056
+ const filepath = `src/${env}_bridge_info.g.ts`
1057
+ await writeFile(filepath, fileContents)
1058
+ })()
1059
+
1060
+ function generateTsObject(value: unknown, indentSize = 4): string {
1061
+ const indentUnit = " ".repeat(indentSize)
1062
+ const serialize = (val: unknown, depth: number): string | undefined => {
1063
+ if (val === null) return "null"
1064
+ if (val === undefined) return undefined
1065
+ if (typeof val === "function" || typeof val === "symbol") return undefined
1066
+ if (typeof val === "bigint") return `${val}n`
1067
+ if (typeof val === "string") return JSON.stringify(val)
1068
+ if (typeof val === "number" || typeof val === "boolean") return String(val)
1069
+ if (Array.isArray(val)) {
1070
+ if (val.length === 0) return "[]"
1071
+ const indent = indentUnit.repeat(depth + 1)
1072
+ const closingIndent = indentUnit.repeat(depth)
1073
+ const items = val
1074
+ .map((item) => {
1075
+ const serialized = serialize(item, depth + 1)
1076
+ return `${indent}${serialized ?? "null"}`
1077
+ })
1078
+ .join(",\n")
1079
+ return `[\n${items}\n${closingIndent}]`
1080
+ }
1081
+ if (typeof val === "object") {
1082
+ const obj = val as Record<string, unknown>
1083
+ const keys = Object.keys(obj)
1084
+ const indent = indentUnit.repeat(depth + 1)
1085
+ const closingIndent = indentUnit.repeat(depth)
1086
+ const items: string[] = []
1087
+ for (const key of keys) {
1088
+ const serialized = serialize(obj[key], depth + 1)
1089
+ if (serialized === undefined) continue
1090
+ const keyLiteral = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)
1091
+ ? key
1092
+ : JSON.stringify(key)
1093
+ items.push(`${indent}${keyLiteral}: ${serialized},`)
661
1094
  }
662
- return value
663
- },
664
- 2,
665
- )
1095
+ if (items.length === 0) return "{}"
1096
+ return `{\n${items.join("\n")}\n${closingIndent}}`
1097
+ }
1098
+ throw new Error(`Unsupported type in registry output: ${typeof val}`)
1099
+ }
666
1100
 
667
- const filepath = `src/${env}.registry.json`
668
- await writeFile(filepath, json)
669
- })()
1101
+ const serialized = serialize(value, 0)
1102
+ if (serialized === undefined) {
1103
+ throw new Error("Registry output is not serializable")
1104
+ }
1105
+ return serialized
1106
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,25 @@
1
- export * from "./environment"
2
- export * from "./registry"
3
1
  export * from "./transfers"
2
+
3
+ import polkadot_mainnet from "./polkadot_mainnet_bridge_info.g"
4
+ import westend_sepolia from "./westend_sepolia_bridge_info.g"
5
+ import paseo_sepolia from "./paseo_sepolia_bridge_info.g"
6
+
7
+ export { paseo_sepolia, westend_sepolia, polkadot_mainnet }
8
+
9
+ import { BridgeInfo } from "@snowbridge/base-types"
10
+
11
+ export function bridgeInfoFor(
12
+ env: "polkadot_mainnet" | "westend_sepolia" | "paseo_sepolia" | (string & {}),
13
+ ): Readonly<BridgeInfo> {
14
+ switch (env) {
15
+ case "polkadot_mainnet":
16
+ return polkadot_mainnet satisfies BridgeInfo
17
+ break
18
+ case "westend_sepolia":
19
+ return westend_sepolia satisfies BridgeInfo
20
+ case "paseo_sepolia":
21
+ return paseo_sepolia satisfies BridgeInfo
22
+ default:
23
+ throw Error(`Unknown env '${env}'`)
24
+ }
25
+ }