@uniswap/token-list-bridge-utils 2.1.0 → 2.2.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.
@@ -3,6 +3,14 @@ import { providers } from 'ethers'
3
3
 
4
4
  const networkID = 42161
5
5
 
6
+ const l2Rpc = (chainId: number) => {
7
+ if (chainId === 42161) return 'https://arb1.arbitrum.io/rpc'
8
+ else if (chainId === 421611) return 'https://rinkeby.arbitrum.io/rpc'
9
+ else if (chainId === 42170) return 'https://nova.arbitrum.io/rpc'
10
+ else if (chainId === 421613) return 'https://goerli-rollup.arbitrum.io/rpc'
11
+ throw new Error('No L2 RPC detected')
12
+ }
13
+
6
14
  // ref: https://github.com/OffchainLabs/arb-token-lists/blob/master/src/lib/instantiate_bridge.ts
7
15
  export const getNetworkConfig = async () => {
8
16
  const { getL1Network, getL2Network, MultiCaller } = await import(
@@ -11,8 +19,8 @@ export const getNetworkConfig = async () => {
11
19
  const l2Network = await getL2Network(networkID)
12
20
  const l1Network = await getL1Network(l2Network.partnerChainID)
13
21
 
14
- const arbProvider = new providers.JsonRpcProvider(l2Network.rpcURL)
15
- const ethProvider = new providers.JsonRpcProvider(l1Network.rpcURL)
22
+ const arbProvider = new providers.JsonRpcProvider(l2Rpc(l2Network.chainID))
23
+ const ethProvider = new providers.JsonRpcProvider(process.env.MAINNET_RPC)
16
24
 
17
25
  const l1MultiCaller = await MultiCaller.fromProvider(ethProvider)
18
26
  const l2MultiCaller = await MultiCaller.fromProvider(arbProvider)
@@ -16,5 +16,6 @@ export enum ChainId {
16
16
 
17
17
  AVALANCHE = 43114,
18
18
 
19
+ BASE = 8453,
19
20
  BASE_GOERLI = 84531,
20
21
  }
@@ -11,7 +11,15 @@ export const COINBASE_WRAPPED_STAKED_ETH = new Token(
11
11
 
12
12
  export const COINBASE_WRAPPED_STAKED_ETH_BASE_GOERLI = new Token(
13
13
  ChainId.BASE_GOERLI,
14
- '0x7c6b91D9Be155A6Db01f749217d76fF02A7227F2',
14
+ '0x4fC531f8Ae7A7808E0dccCA08F1e3c7694582950',
15
+ 18,
16
+ 'cbETH',
17
+ 'Coinbase Wrapped Staked ETH'
18
+ )
19
+
20
+ export const COINBASE_WRAPPED_STAKED_ETH_BASE = new Token(
21
+ ChainId.BASE,
22
+ '0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22',
15
23
  18,
16
24
  'cbETH',
17
25
  'Coinbase Wrapped Staked ETH'
@@ -25,6 +33,14 @@ export const COINBASE_WRAPPED_STAKED_ETH_ARBITRUM_ONE = new Token(
25
33
  'Coinbase Wrapped Staked ETH'
26
34
  )
27
35
 
36
+ export const COINBASE_WRAPPED_STAKED_ETH_OPTIMISM = new Token(
37
+ ChainId.OPTIMISM,
38
+ '0xadDb6A0412DE1BA0F936DCaeb8Aaa24578dcF3B2',
39
+ 18,
40
+ 'cbETH',
41
+ 'Coinbase Wrapped Staked ETH'
42
+ )
43
+
28
44
  export const DAI = new Token(
29
45
  ChainId.MAINNET,
30
46
  '0x6B175474E89094C44Da98b954EedeAC495271d0F',
@@ -70,6 +86,22 @@ export const DAI_AVALANCHE = new Token(
70
86
  'DAI.e'
71
87
  )
72
88
 
89
+ export const DAI_BASE = new Token(
90
+ ChainId.BASE,
91
+ '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
92
+ 18,
93
+ 'DAI',
94
+ 'Dai Stablecoin'
95
+ )
96
+
97
+ export const DAI_BASE_GOERLI = new Token(
98
+ ChainId.BASE_GOERLI,
99
+ '0x174956bDfbCEb6e53089297cce4fE2825E58d92C',
100
+ 18,
101
+ 'DAI',
102
+ 'Dai Stablecoin'
103
+ )
104
+
73
105
  export const USDT = new Token(
74
106
  ChainId.MAINNET,
75
107
  '0xdAC17F958D2ee523a2206206994597C13D831ec7',
@@ -13,6 +13,10 @@ import {
13
13
  COINBASE_WRAPPED_STAKED_ETH,
14
14
  COINBASE_WRAPPED_STAKED_ETH_BASE_GOERLI,
15
15
  COINBASE_WRAPPED_STAKED_ETH_ARBITRUM_ONE,
16
+ COINBASE_WRAPPED_STAKED_ETH_BASE,
17
+ DAI_BASE_GOERLI,
18
+ COINBASE_WRAPPED_STAKED_ETH_OPTIMISM,
19
+ DAI_BASE,
16
20
  } from '../constants/tokens'
17
21
  import { compareTokenInfos } from '../utils'
18
22
 
@@ -33,6 +37,9 @@ export const Tokens: Partial<Record<ChainId, Record<string, TokenInfo>>> = {
33
37
  },
34
38
  [ChainId.OPTIMISM]: {
35
39
  DAI: tokenToTokenInfo(DAI_OPTIMISM),
40
+ COINBASE_WRAPPED_STAKED_ETH: tokenToTokenInfo(
41
+ COINBASE_WRAPPED_STAKED_ETH_OPTIMISM
42
+ ),
36
43
  },
37
44
  [ChainId.BNB]: {
38
45
  DAI: tokenToTokenInfo(DAI_BNB),
@@ -41,7 +48,14 @@ export const Tokens: Partial<Record<ChainId, Record<string, TokenInfo>>> = {
41
48
  [ChainId.AVALANCHE]: {
42
49
  DAI: tokenToTokenInfo(DAI_AVALANCHE),
43
50
  },
51
+ [ChainId.BASE]: {
52
+ DAI: tokenToTokenInfo(DAI_BASE),
53
+ COINBASE_WRAPPED_STAKED_ETH: tokenToTokenInfo(
54
+ COINBASE_WRAPPED_STAKED_ETH_BASE
55
+ ),
56
+ },
44
57
  [ChainId.BASE_GOERLI]: {
58
+ DAI: tokenToTokenInfo(DAI_BASE_GOERLI),
45
59
  COINBASE_WRAPPED_STAKED_ETH: tokenToTokenInfo(
46
60
  COINBASE_WRAPPED_STAKED_ETH_BASE_GOERLI
47
61
  ),
@@ -250,6 +264,34 @@ export const baseGoerliSampleTokenList_3 = {
250
264
  ].sort(compareTokenInfos),
251
265
  }
252
266
 
267
+ export const baseSampleTokenList_3 = {
268
+ ...sampleL1TokenList_3,
269
+ name: 'Base Sample_3',
270
+ tokens: [
271
+ {
272
+ ...Tokens[ChainId.BASE]!.COINBASE_WRAPPED_STAKED_ETH,
273
+ extensions: {
274
+ bridgeInfo: {
275
+ [ChainId.MAINNET]: {
276
+ tokenAddress: COINBASE_WRAPPED_STAKED_ETH.address,
277
+ },
278
+ },
279
+ },
280
+ } as unknown as TokenInfo,
281
+ {
282
+ ...(Tokens[ChainId.MAINNET]!
283
+ .COINBASE_WRAPPED_STAKED_ETH as unknown as TokenInfo),
284
+ extensions: {
285
+ bridgeInfo: {
286
+ [ChainId.BASE]: {
287
+ tokenAddress: COINBASE_WRAPPED_STAKED_ETH_BASE.address,
288
+ },
289
+ },
290
+ },
291
+ } as unknown as TokenInfo,
292
+ ].sort(compareTokenInfos),
293
+ }
294
+
253
295
  export const optimizedSampleTokenList = {
254
296
  ...sampleL1TokenList,
255
297
  name: 'Optimized Sample',
package/src/index.test.ts CHANGED
@@ -4,10 +4,14 @@ import { ChainId } from './constants/chainId'
4
4
  import {
5
5
  COINBASE_WRAPPED_STAKED_ETH,
6
6
  COINBASE_WRAPPED_STAKED_ETH_ARBITRUM_ONE,
7
+ COINBASE_WRAPPED_STAKED_ETH_BASE,
7
8
  COINBASE_WRAPPED_STAKED_ETH_BASE_GOERLI,
9
+ COINBASE_WRAPPED_STAKED_ETH_OPTIMISM,
8
10
  DAI,
9
11
  DAI_ARBITRUM_ONE,
10
12
  DAI_AVALANCHE,
13
+ DAI_BASE,
14
+ DAI_BASE_GOERLI,
11
15
  DAI_BNB,
12
16
  DAI_OPTIMISM,
13
17
  DAI_POLYGON,
@@ -24,6 +28,7 @@ import {
24
28
  avalanchedSampleTokenList,
25
29
  sampleL1TokenList_3,
26
30
  baseGoerliSampleTokenList_3,
31
+ baseSampleTokenList_3,
27
32
  } from './fixtures'
28
33
 
29
34
  jest.setTimeout(15000)
@@ -160,6 +165,22 @@ it('outputs base goerli list correctly', async () => {
160
165
  )
161
166
  })
162
167
 
168
+ it('outputs base list correctly', async () => {
169
+ const tokenList = await chainifyTokenList([ChainId.BASE], sampleL1TokenList_3)
170
+ expect(tokenList).toBeDefined()
171
+ expect(tokenList?.version).toEqual(baseSampleTokenList_3.version)
172
+ expect(
173
+ tokenList?.tokens.map((t) => [t.address, t.chainId, t.extensions])
174
+ ).toEqual(
175
+ // ignores other metadata
176
+ baseSampleTokenList_3.tokens.map((t) => [
177
+ t.address,
178
+ t.chainId,
179
+ t.extensions,
180
+ ])
181
+ )
182
+ })
183
+
163
184
  describe(mergeTokenLists, () => {
164
185
  it('correctly deduplicates', () => {
165
186
  const merged = mergeTokenLists(sampleL1TokenList, sampleL1TokenList)
@@ -255,32 +276,11 @@ describe(mergeTokenLists, () => {
255
276
  })
256
277
  })
257
278
  describe(chainify, () => {
258
- it('creates tokenMap correctly in chainify', async () => {
279
+ it('provides bridge extensions', async () => {
259
280
  const chainified = await chainify(sampleL1TokenList)
260
281
 
261
- expect(chainified.tokenMap).toEqual({
262
- '10_0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1': {
263
- ...Tokens[ChainId.OPTIMISM]!.DAI,
264
- name: 'Dai Stablecoin',
265
- extensions: {
266
- bridgeInfo: {
267
- [ChainId.MAINNET]: {
268
- tokenAddress: DAI.address,
269
- },
270
- },
271
- },
272
- },
273
- '137_0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063': {
274
- ...Tokens[ChainId.POLYGON]!.DAI,
275
- extensions: {
276
- bridgeInfo: {
277
- [ChainId.MAINNET]: {
278
- tokenAddress: DAI.address,
279
- },
280
- },
281
- },
282
- },
283
- '1_0x6B175474E89094C44Da98b954EedeAC495271d0F': {
282
+ expect(chainified.tokens).toEqual([
283
+ {
284
284
  ...Tokens[ChainId.MAINNET]!.DAI,
285
285
  extensions: {
286
286
  bridgeInfo: {
@@ -301,26 +301,18 @@ describe(chainify, () => {
301
301
  // destBridgeAddress: arbBridgeL2Address,
302
302
  // originBridgeAddress: arbBridgeL1Address,
303
303
  },
304
- },
305
- },
306
- },
307
- '42161_0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1': {
308
- ...Tokens[ChainId.ARBITRUM_ONE]!.DAI,
309
- extensions: {
310
- bridgeInfo: {
311
- [ChainId.MAINNET]: {
312
- tokenAddress: DAI.address,
313
- // originBridgeAddress: arbBridgeL2Address,
314
- // destBridgeAddress: arbBridgeL1Address,
304
+ [ChainId.BASE]: {
305
+ tokenAddress: DAI_BASE.address,
306
+ },
307
+ [ChainId.BASE_GOERLI]: {
308
+ tokenAddress: DAI_BASE_GOERLI.address,
315
309
  },
316
310
  },
317
311
  },
318
- name: 'Dai Stablecoin',
319
312
  },
320
- '43114_0xd586E7F844cEa2F87f50152665BCbc2C279D8d70': {
321
- ...Tokens[ChainId.AVALANCHE]!.DAI,
313
+ {
314
+ ...Tokens[ChainId.OPTIMISM]!.DAI,
322
315
  name: 'Dai Stablecoin',
323
- symbol: 'DAI',
324
316
  extensions: {
325
317
  bridgeInfo: {
326
318
  [ChainId.MAINNET]: {
@@ -329,7 +321,7 @@ describe(chainify, () => {
329
321
  },
330
322
  },
331
323
  },
332
- '56_0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3': {
324
+ {
333
325
  ...Tokens[ChainId.BNB]!.DAI,
334
326
  extensions: {
335
327
  bridgeInfo: {
@@ -339,40 +331,8 @@ describe(chainify, () => {
339
331
  },
340
332
  },
341
333
  },
342
- })
343
- })
344
-
345
- it('provides bridge extensions', async () => {
346
- const chainified = await chainify(sampleL1TokenList)
347
-
348
- expect(chainified.tokens).toEqual([
349
- {
350
- ...Tokens[ChainId.MAINNET]!.DAI,
351
- extensions: {
352
- bridgeInfo: {
353
- [ChainId.BNB]: {
354
- tokenAddress: DAI_BNB.address,
355
- },
356
- [ChainId.AVALANCHE]: {
357
- tokenAddress: DAI_AVALANCHE.address,
358
- },
359
- [ChainId.OPTIMISM]: {
360
- tokenAddress: DAI_OPTIMISM.address,
361
- },
362
- [ChainId.POLYGON]: {
363
- tokenAddress: DAI_POLYGON.address,
364
- },
365
- [ChainId.ARBITRUM_ONE]: {
366
- tokenAddress: DAI_ARBITRUM_ONE.address,
367
- // destBridgeAddress: arbBridgeL2Address,
368
- // originBridgeAddress: arbBridgeL1Address,
369
- },
370
- },
371
- },
372
- },
373
334
  {
374
- ...Tokens[ChainId.OPTIMISM]!.DAI,
375
- name: 'Dai Stablecoin',
335
+ ...Tokens[ChainId.POLYGON]!.DAI,
376
336
  extensions: {
377
337
  bridgeInfo: {
378
338
  [ChainId.MAINNET]: {
@@ -382,7 +342,7 @@ describe(chainify, () => {
382
342
  },
383
343
  },
384
344
  {
385
- ...Tokens[ChainId.BNB]!.DAI,
345
+ ...Tokens[ChainId.BASE]!.DAI,
386
346
  extensions: {
387
347
  bridgeInfo: {
388
348
  [ChainId.MAINNET]: {
@@ -392,32 +352,32 @@ describe(chainify, () => {
392
352
  },
393
353
  },
394
354
  {
395
- ...Tokens[ChainId.POLYGON]!.DAI,
355
+ ...Tokens[ChainId.ARBITRUM_ONE]!.DAI,
396
356
  extensions: {
397
357
  bridgeInfo: {
398
358
  [ChainId.MAINNET]: {
399
359
  tokenAddress: DAI.address,
360
+ // originBridgeAddress: arbBridgeL2Address,
361
+ // destBridgeAddress: arbBridgeL1Address,
400
362
  },
401
363
  },
402
364
  },
365
+ name: 'Dai Stablecoin',
403
366
  },
404
367
  {
405
- ...Tokens[ChainId.ARBITRUM_ONE]!.DAI,
368
+ ...Tokens[ChainId.AVALANCHE]!.DAI,
369
+ name: 'Dai Stablecoin',
370
+ symbol: 'DAI',
406
371
  extensions: {
407
372
  bridgeInfo: {
408
373
  [ChainId.MAINNET]: {
409
374
  tokenAddress: DAI.address,
410
- // originBridgeAddress: arbBridgeL2Address,
411
- // destBridgeAddress: arbBridgeL1Address,
412
375
  },
413
376
  },
414
377
  },
415
- name: 'Dai Stablecoin',
416
378
  },
417
379
  {
418
- ...Tokens[ChainId.AVALANCHE]!.DAI,
419
- name: 'Dai Stablecoin',
420
- symbol: 'DAI',
380
+ ...Tokens[ChainId.BASE_GOERLI]!.DAI,
421
381
  extensions: {
422
382
  bridgeInfo: {
423
383
  [ChainId.MAINNET]: {
@@ -429,7 +389,7 @@ describe(chainify, () => {
429
389
  ])
430
390
  })
431
391
 
432
- it('provides bridge extensions for base goerli list', async () => {
392
+ it('provides bridge extensions for base list', async () => {
433
393
  const chainified = await chainify(sampleL1TokenList_3)
434
394
 
435
395
  expect(chainified.tokens).toEqual([
@@ -437,12 +397,40 @@ describe(chainify, () => {
437
397
  ...Tokens[ChainId.MAINNET]!.COINBASE_WRAPPED_STAKED_ETH,
438
398
  extensions: {
439
399
  bridgeInfo: {
440
- [ChainId.ARBITRUM_ONE]: {
441
- tokenAddress: COINBASE_WRAPPED_STAKED_ETH_ARBITRUM_ONE.address,
400
+ [ChainId.OPTIMISM]: {
401
+ tokenAddress: COINBASE_WRAPPED_STAKED_ETH_OPTIMISM.address,
402
+ },
403
+ [ChainId.BASE]: {
404
+ tokenAddress: COINBASE_WRAPPED_STAKED_ETH_BASE.address,
442
405
  },
443
406
  [ChainId.BASE_GOERLI]: {
444
407
  tokenAddress: COINBASE_WRAPPED_STAKED_ETH_BASE_GOERLI.address,
445
408
  },
409
+ [ChainId.ARBITRUM_ONE]: {
410
+ tokenAddress: COINBASE_WRAPPED_STAKED_ETH_ARBITRUM_ONE.address,
411
+ },
412
+ },
413
+ },
414
+ },
415
+ {
416
+ ...Tokens[ChainId.OPTIMISM]!.COINBASE_WRAPPED_STAKED_ETH,
417
+ name: 'Coinbase Wrapped Staked ETH',
418
+ extensions: {
419
+ bridgeInfo: {
420
+ [ChainId.MAINNET]: {
421
+ tokenAddress: COINBASE_WRAPPED_STAKED_ETH.address,
422
+ },
423
+ },
424
+ },
425
+ },
426
+ {
427
+ ...Tokens[ChainId.BASE]!.COINBASE_WRAPPED_STAKED_ETH,
428
+ name: 'Coinbase Wrapped Staked ETH',
429
+ extensions: {
430
+ bridgeInfo: {
431
+ [ChainId.MAINNET]: {
432
+ tokenAddress: COINBASE_WRAPPED_STAKED_ETH.address,
433
+ },
446
434
  },
447
435
  },
448
436
  },
package/src/index.ts CHANGED
@@ -25,6 +25,7 @@ export async function chainify(
25
25
  ChainId.CELO,
26
26
  ChainId.BNB,
27
27
  ChainId.AVALANCHE,
28
+ ChainId.BASE,
28
29
  ChainId.BASE_GOERLI,
29
30
  ]
30
31
 
@@ -34,13 +35,7 @@ export async function chainify(
34
35
  chainified
35
36
  )
36
37
 
37
- const tokenMap = {}
38
- if (merged.tokens && merged.tokens.length > 0) {
39
- merged.tokens.forEach((token) => {
40
- tokenMap[`${token.chainId}_${token.address}`] = token
41
- })
42
- }
43
- return { ...merged, tokenMap }
38
+ return merged
44
39
  }
45
40
 
46
41
  /**
@@ -81,7 +76,10 @@ export function mergeTokenLists(
81
76
  }
82
77
 
83
78
  const merged = merge(group[0], group[1])
84
- if (merged.extensions?.bridgeInfo) {
79
+ if (
80
+ merged.extensions?.bridgeInfo &&
81
+ typeof merged.extensions.bridgeInfo === 'object'
82
+ ) {
85
83
  // remove reference to self-chain from merge
86
84
  delete merged.extensions.bridgeInfo[merged.chainId]
87
85
  }
@@ -17,7 +17,7 @@ export class BaseGoerliMappingProvider implements MappingProvider {
17
17
 
18
18
  let allTokens = await getTokenList(baseGoerliTokenListURL)
19
19
 
20
- let opTokenId_baseGoerliAddressMap = {}
20
+ let opTokenId_baseGoerliAddressMap: Record<string, string> = {}
21
21
  allTokens.tokens.forEach((token) => {
22
22
  if (token.chainId === ChainId.BASE_GOERLI) {
23
23
  if (typeof token.extensions?.opTokenId === 'string') {
@@ -0,0 +1,42 @@
1
+ import { MappingProvider } from './MappingProvider'
2
+ import { ChainId } from '../constants/chainId'
3
+ import { getTokenList } from '../utils'
4
+ import { GenericMappedTokenData } from '../constants/types'
5
+
6
+ const baseGoerliTokenListURL =
7
+ 'https://raw.githubusercontent.com/' +
8
+ 'ethereum-optimism/ethereum-optimism.github.io/master/optimism.tokenlist.json'
9
+
10
+ /**
11
+ * The Base mapping (linked above) is manually maintained by the Coinbase team
12
+ * in this repository: https://github.com/ethereum-optimism/ethereum-optimism.github.io.
13
+ */
14
+ export class BaseMappingProvider implements MappingProvider {
15
+ async provide(): Promise<GenericMappedTokenData> {
16
+ const tokens: { [key: string]: string | undefined } = {}
17
+
18
+ let allTokens = await getTokenList(baseGoerliTokenListURL)
19
+
20
+ let opTokenId_baseAddressMap: Record<string, string> = {}
21
+ allTokens.tokens.forEach((token) => {
22
+ if (token.chainId === ChainId.BASE) {
23
+ if (typeof token.extensions?.opTokenId === 'string') {
24
+ opTokenId_baseAddressMap[token.extensions.opTokenId] = token.address
25
+ }
26
+ }
27
+ })
28
+
29
+ allTokens.tokens.forEach((token) => {
30
+ if (
31
+ token.chainId === ChainId.MAINNET &&
32
+ typeof token.extensions?.opTokenId === 'string' &&
33
+ token.extensions!.opTokenId in opTokenId_baseAddressMap
34
+ ) {
35
+ tokens[token.address.toLowerCase()] =
36
+ opTokenId_baseAddressMap[token.extensions!.opTokenId]
37
+ }
38
+ })
39
+
40
+ return tokens
41
+ }
42
+ }
@@ -5,7 +5,7 @@ import { GenericMappedTokenData } from '../constants/types'
5
5
 
6
6
  const optimismTokenListURL =
7
7
  'https://raw.githubusercontent.com/' +
8
- 'ethereum-optimism/ethereum-optimism.github.io/2138386277e4156d159615d1840882cecc398437/optimism.tokenlist.json'
8
+ 'ethereum-optimism/ethereum-optimism.github.io/master/optimism.tokenlist.json'
9
9
 
10
10
  /**
11
11
  * The Optimism L2 mapping (linked above) is manually maintained by the Optimism team.
@@ -16,14 +16,27 @@ export class OptimismMappingProvider implements MappingProvider {
16
16
  async provide(): Promise<GenericMappedTokenData> {
17
17
  const tokens: { [key: string]: string | undefined } = {}
18
18
 
19
- let optimismTokens = await getTokenList(optimismTokenListURL)
19
+ let allTokens = await getTokenList(optimismTokenListURL)
20
20
 
21
- for (const token of optimismTokens.tokens) {
22
- if (token.chainId === ChainId.MAINNET) {
21
+ let opTokenId_baseAddressMap: Record<string, string> = {}
22
+ allTokens.tokens.forEach((token) => {
23
+ if (token.chainId === ChainId.OPTIMISM) {
24
+ if (typeof token.extensions?.opTokenId === 'string') {
25
+ opTokenId_baseAddressMap[token.extensions.opTokenId] = token.address
26
+ }
27
+ }
28
+ })
29
+
30
+ allTokens.tokens.forEach((token) => {
31
+ if (
32
+ token.chainId === ChainId.MAINNET &&
33
+ typeof token.extensions?.opTokenId === 'string' &&
34
+ token.extensions!.opTokenId in opTokenId_baseAddressMap
35
+ ) {
23
36
  tokens[token.address.toLowerCase()] =
24
- token?.extensions?.bridgeInfo![ChainId.OPTIMISM].tokenAddress
37
+ opTokenId_baseAddressMap[token.extensions!.opTokenId]
25
38
  }
26
- }
39
+ })
27
40
 
28
41
  return tokens
29
42
  }
@@ -22,6 +22,7 @@ import {
22
22
  } from '../constants/types'
23
23
  import { AvalancheMappingProvider } from './AvalancheMappingProvider'
24
24
  import { BaseGoerliMappingProvider } from './BaseGoerliMappingProvider'
25
+ import { BaseMappingProvider } from './BaseMappingProvider'
25
26
 
26
27
  const web3 = new Web3()
27
28
 
@@ -32,6 +33,7 @@ const CHAINS_WITH_MAPPING_PROVIDERS = [
32
33
  ChainId.OPTIMISM,
33
34
  ChainId.BNB,
34
35
  ChainId.AVALANCHE,
36
+ ChainId.BASE,
35
37
  ChainId.BASE_GOERLI,
36
38
  ]
37
39
 
@@ -55,7 +57,7 @@ export async function buildList(
55
57
  } = {}
56
58
  const l2MappingExtension = {
57
59
  extensions: {
58
- bridgeInfo: {},
60
+ bridgeInfo: {} as any,
59
61
  },
60
62
  }
61
63
  // build out the extensions.bridgeInfo data containing mappings for each L2 chain
@@ -133,7 +135,7 @@ async function hasExistingTokenContract(address: string, chainId: ChainId) {
133
135
  try {
134
136
  const contract: Contract = new web3.eth.Contract(ERC20Abi, address)
135
137
  await getTokenSymbolFromContract(contract)
136
- } catch {
138
+ } catch (e) {
137
139
  return false
138
140
  }
139
141
 
@@ -152,6 +154,8 @@ function getMappingProvider(chainId: ChainId, l1TokenList: TokenList) {
152
154
  return new BnbMappingProvider()
153
155
  case ChainId.AVALANCHE:
154
156
  return new AvalancheMappingProvider()
157
+ case ChainId.BASE:
158
+ return new BaseMappingProvider()
155
159
  case ChainId.BASE_GOERLI:
156
160
  return new BaseGoerliMappingProvider()
157
161
  default:
@@ -197,8 +201,14 @@ async function getChildTokenDetails(
197
201
  childTokenAddress: string | undefined
198
202
  decimals?: number | undefined
199
203
  }> {
200
- const existingMapping: undefined | string =
201
- l1Token?.extensions?.bridgeInfo?.[chainId]?.tokenAddress
204
+ const bridgeInfo = l1Token?.extensions?.bridgeInfo
205
+ let existingMapping: undefined | string
206
+ if (bridgeInfo && typeof bridgeInfo === 'object') {
207
+ const bridgeInfoForChain = bridgeInfo[chainId]
208
+ if (bridgeInfoForChain && typeof bridgeInfoForChain === 'object') {
209
+ existingMapping = bridgeInfoForChain.tokenAddress as string
210
+ }
211
+ }
202
212
  // use the externally fetched mappings if manual entry doesn't exist for the token/chain mapping
203
213
  // and the given chain is supported for fetching mappings
204
214
  if (
@@ -221,7 +231,6 @@ async function getChildTokenDetails(
221
231
  childToken && (chainId === ChainId.BNB || chainId === ChainId.AVALANCHE)
222
232
  ? (childToken as MappedToken).decimals
223
233
  : undefined
224
-
225
234
  return {
226
235
  childTokenValid: childTokenValid,
227
236
  childTokenAddress: childTokenAddress,
package/src/utils.ts CHANGED
@@ -112,6 +112,8 @@ export function getRpcUrl(chainId: ChainId): string {
112
112
  return 'https://bsc-dataseed1.binance.org'
113
113
  case ChainId.AVALANCHE:
114
114
  return 'https://api.avax.network/ext/bc/C/rpc'
115
+ case ChainId.BASE:
116
+ return 'https://mainnet.base.org'
115
117
  case ChainId.BASE_GOERLI:
116
118
  return 'https://goerli.base.org'
117
119
  default: