@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.
- package/dist/constants/chainId.d.ts +1 -0
- package/dist/constants/tokens.d.ts +4 -0
- package/dist/fixtures/index.d.ts +12 -0
- package/dist/providers/BaseMappingProvider.d.ts +9 -0
- package/dist/token-list-bridge-utils.cjs.development.js +122 -42
- package/dist/token-list-bridge-utils.cjs.development.js.map +1 -1
- package/dist/token-list-bridge-utils.cjs.production.min.js +1 -1
- package/dist/token-list-bridge-utils.cjs.production.min.js.map +1 -1
- package/dist/token-list-bridge-utils.esm.js +122 -42
- package/dist/token-list-bridge-utils.esm.js.map +1 -1
- package/package.json +14 -23
- package/src/arbitrum/instantiate_bridge.ts +10 -2
- package/src/constants/chainId.ts +1 -0
- package/src/constants/tokens.ts +33 -1
- package/src/fixtures/index.ts +42 -0
- package/src/index.test.ts +73 -85
- package/src/index.ts +6 -8
- package/src/providers/BaseGoerliMappingProvider.ts +1 -1
- package/src/providers/BaseMappingProvider.ts +42 -0
- package/src/providers/OptimismMappingProvider.ts +19 -6
- package/src/providers/index.ts +14 -5
- package/src/utils.ts +2 -0
|
@@ -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.
|
|
15
|
-
const ethProvider = new providers.JsonRpcProvider(
|
|
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)
|
package/src/constants/chainId.ts
CHANGED
package/src/constants/tokens.ts
CHANGED
|
@@ -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
|
-
'
|
|
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',
|
package/src/fixtures/index.ts
CHANGED
|
@@ -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('
|
|
279
|
+
it('provides bridge extensions', async () => {
|
|
259
280
|
const chainified = await chainify(sampleL1TokenList)
|
|
260
281
|
|
|
261
|
-
expect(chainified.
|
|
262
|
-
|
|
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
|
-
|
|
308
|
-
|
|
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
|
-
|
|
321
|
-
...Tokens[ChainId.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
441
|
-
tokenAddress:
|
|
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
|
-
|
|
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 (
|
|
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/
|
|
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
|
|
19
|
+
let allTokens = await getTokenList(optimismTokenListURL)
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
37
|
+
opTokenId_baseAddressMap[token.extensions!.opTokenId]
|
|
25
38
|
}
|
|
26
|
-
}
|
|
39
|
+
})
|
|
27
40
|
|
|
28
41
|
return tokens
|
|
29
42
|
}
|
package/src/providers/index.ts
CHANGED
|
@@ -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
|
|
201
|
-
|
|
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:
|