@uniswap/token-list-bridge-utils 0.1.1-beta.1 → 1.0.1

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 (56) hide show
  1. package/README.md +102 -5
  2. package/dist/arbitrum/gateway.d.ts +2 -0
  3. package/dist/{arb-token-lists/src/lib → arbitrum}/instantiate_bridge.d.ts +3 -4
  4. package/dist/constants/types.d.ts +30 -0
  5. package/dist/fixtures/index.d.ts +9 -0
  6. package/dist/providers/ArbitrumMappingProvider.d.ts +7 -6
  7. package/dist/providers/MappingProvider.d.ts +4 -2
  8. package/dist/providers/OptimismMappingProvider.d.ts +5 -4
  9. package/dist/providers/PolygonMappingProvider.d.ts +4 -2
  10. package/dist/providers/index.d.ts +2 -4
  11. package/dist/token-list-bridge-utils.cjs.development.js +327 -906
  12. package/dist/token-list-bridge-utils.cjs.development.js.map +1 -1
  13. package/dist/token-list-bridge-utils.cjs.production.min.js +1 -1
  14. package/dist/token-list-bridge-utils.cjs.production.min.js.map +1 -1
  15. package/dist/token-list-bridge-utils.esm.js +329 -902
  16. package/dist/token-list-bridge-utils.esm.js.map +1 -1
  17. package/dist/utils.d.ts +4 -0
  18. package/package.json +7 -4
  19. package/src/.DS_Store +0 -0
  20. package/src/arbitrum/gateway.ts +25 -0
  21. package/src/{arb-token-lists/src/lib → arbitrum}/instantiate_bridge.ts +11 -15
  22. package/src/constants/types.ts +28 -0
  23. package/src/fixtures/index.ts +40 -5
  24. package/src/index.test.ts +60 -18
  25. package/src/index.ts +5 -7
  26. package/src/providers/ArbitrumMappingProvider.ts +31 -21
  27. package/src/providers/MappingProvider.ts +4 -2
  28. package/src/providers/OptimismMappingProvider.ts +21 -5
  29. package/src/providers/PolygonMappingProvider.ts +22 -114
  30. package/src/providers/index.ts +82 -2
  31. package/src/utils.ts +71 -1
  32. package/dist/arb-token-lists/server/app.d.ts +0 -1
  33. package/dist/arb-token-lists/src/lib/getClargs.d.ts +0 -8
  34. package/dist/arb-token-lists/src/lib/graph.d.ts +0 -2
  35. package/dist/arb-token-lists/src/lib/token_list_gen.d.ts +0 -23
  36. package/dist/arb-token-lists/src/lib/types.d.ts +0 -36
  37. package/dist/arb-token-lists/src/lib/utils.d.ts +0 -18
  38. package/dist/arb-token-lists/src/main.d.ts +0 -1
  39. package/src/arb-token-lists/.env.sample +0 -4
  40. package/src/arb-token-lists/.eslintrc.js +0 -43
  41. package/src/arb-token-lists/.gitignore +0 -4
  42. package/src/arb-token-lists/package.json +0 -40
  43. package/src/arb-token-lists/readme.md +0 -14
  44. package/src/arb-token-lists/server/app.ts +0 -21
  45. package/src/arb-token-lists/src/Assets/coingecko_uris.json +0 -5108
  46. package/src/arb-token-lists/src/Assets/logo_uris.json +0 -44
  47. package/src/arb-token-lists/src/WarningList/warningTokens.json +0 -290
  48. package/src/arb-token-lists/src/lib/getClargs.ts +0 -32
  49. package/src/arb-token-lists/src/lib/graph.ts +0 -116
  50. package/src/arb-token-lists/src/lib/token_list_gen.ts +0 -334
  51. package/src/arb-token-lists/src/lib/types.ts +0 -44
  52. package/src/arb-token-lists/src/lib/utils.ts +0 -285
  53. package/src/arb-token-lists/src/main.ts +0 -54
  54. package/src/arb-token-lists/tsconfig.json +0 -20
  55. package/src/arb-token-lists/update_all +0 -6
  56. package/src/arb-token-lists/yarn.lock +0 -4273
@@ -0,0 +1,28 @@
1
+ export interface PolygonMappedToken {
2
+ chainId: number
3
+ child_address_passed_by_user: boolean
4
+ child_token: string
5
+ count: number
6
+ created_at: string
7
+ decimals: number
8
+ deleted: boolean
9
+ id: number
10
+ map_type: 'POS'
11
+ mintable: boolean
12
+ name: string
13
+ new_child_token: string
14
+ new_mintable: boolean
15
+ owner: string
16
+ reason: string
17
+ reason_for_remapping: string
18
+ remapping_allowed: boolean
19
+ remapping_request_submitted: boolean
20
+ remapping_verified: boolean
21
+ root_token: string
22
+ status: number
23
+ symbol: string
24
+ token_type: string // ERC20
25
+ updated_at: string
26
+ uri: string
27
+ }
28
+ export type PolygonMappedTokenData = { [key: string]: PolygonMappedToken }
@@ -1,7 +1,12 @@
1
1
  import { Token } from '@uniswap/sdk-core'
2
2
  import { TokenInfo, TokenList } from '@uniswap/token-lists'
3
3
  import { ChainId } from '../constants/chainId'
4
- import { DAI, DAI_ARBITRUM_ONE, DAI_POLYGON } from '../constants/tokens'
4
+ import {
5
+ DAI,
6
+ DAI_ARBITRUM_ONE,
7
+ DAI_OPTIMISM,
8
+ DAI_POLYGON,
9
+ } from '../constants/tokens'
5
10
  import { compareTokenInfos } from '../utils'
6
11
 
7
12
  export const Tokens: Partial<Record<ChainId, Record<string, TokenInfo>>> = {
@@ -14,6 +19,9 @@ export const Tokens: Partial<Record<ChainId, Record<string, TokenInfo>>> = {
14
19
  [ChainId.POLYGON]: {
15
20
  DAI: tokenToTokenInfo(DAI_POLYGON),
16
21
  },
22
+ [ChainId.OPTIMISM]: {
23
+ DAI: tokenToTokenInfo(DAI_OPTIMISM),
24
+ },
17
25
  }
18
26
 
19
27
  export const sampleL1TokenList: TokenList = {
@@ -40,8 +48,8 @@ export const arbedSampleTokenList = {
40
48
  bridgeInfo: {
41
49
  [ChainId.MAINNET]: {
42
50
  tokenAddress: DAI.address,
43
- originBridgeAddress: arbBridgeL2Address,
44
- destBridgeAddress: arbBridgeL1Address,
51
+ // originBridgeAddress: arbBridgeL2Address,
52
+ // destBridgeAddress: arbBridgeL1Address,
45
53
  },
46
54
  },
47
55
  },
@@ -52,8 +60,8 @@ export const arbedSampleTokenList = {
52
60
  bridgeInfo: {
53
61
  [ChainId.ARBITRUM_ONE]: {
54
62
  tokenAddress: DAI_ARBITRUM_ONE.address,
55
- destBridgeAddress: arbBridgeL2Address,
56
- originBridgeAddress: arbBridgeL1Address,
63
+ // destBridgeAddress: arbBridgeL2Address,
64
+ // originBridgeAddress: arbBridgeL1Address,
57
65
  },
58
66
  },
59
67
  },
@@ -87,6 +95,33 @@ export const polygonedSampleTokenList = {
87
95
  ].sort(compareTokenInfos),
88
96
  }
89
97
 
98
+ export const optimizedSampleTokenList = {
99
+ ...sampleL1TokenList,
100
+ name: 'Optimized Sample',
101
+ tokens: [
102
+ {
103
+ ...Tokens[ChainId.OPTIMISM]!.DAI,
104
+ extensions: {
105
+ bridgeInfo: {
106
+ [ChainId.MAINNET]: {
107
+ tokenAddress: DAI.address,
108
+ },
109
+ },
110
+ },
111
+ } as unknown as TokenInfo,
112
+ {
113
+ ...(Tokens[ChainId.MAINNET]!.DAI as unknown as TokenInfo),
114
+ extensions: {
115
+ bridgeInfo: {
116
+ [ChainId.OPTIMISM]: {
117
+ tokenAddress: DAI_OPTIMISM.address,
118
+ },
119
+ },
120
+ },
121
+ } as unknown as TokenInfo,
122
+ ].sort(compareTokenInfos),
123
+ }
124
+
90
125
  function tokenToTokenInfo({
91
126
  chainId,
92
127
  address,
package/src/index.test.ts CHANGED
@@ -1,27 +1,46 @@
1
1
  import { TokenInfo } from '@uniswap/token-lists'
2
2
  import { chainify, chainifyTokenList, mergeTokenLists } from '.'
3
3
  import { ChainId } from './constants/chainId'
4
- import { DAI, DAI_ARBITRUM_ONE, DAI_POLYGON } from './constants/tokens'
4
+ import { ArbitrumMappingProvider } from './providers/ArbitrumMappingProvider'
5
+ import {
6
+ DAI,
7
+ DAI_ARBITRUM_ONE,
8
+ DAI_OPTIMISM,
9
+ DAI_POLYGON,
10
+ } from './constants/tokens'
5
11
  import {
6
- arbBridgeL1Address,
7
- arbBridgeL2Address,
8
12
  arbedSampleTokenList,
13
+ optimizedSampleTokenList,
9
14
  polygonedSampleTokenList,
10
15
  sampleL1TokenList,
11
16
  Tokens,
12
17
  } from './fixtures'
13
18
 
19
+ jest.setTimeout(15000)
20
+
14
21
  describe(chainifyTokenList, () => {
15
- it('no-ops on Optimism', async () => {
22
+ it('outputs Optimism list correctly', async () => {
16
23
  const tokenList = await chainifyTokenList(
17
- ChainId.ARBITRUM_ONE,
24
+ ChainId.OPTIMISM,
18
25
  sampleL1TokenList
19
26
  )
20
27
 
21
- expect(tokenList).toEqual(tokenList)
28
+ expect(tokenList).toBeDefined()
29
+ expect(tokenList?.version).toEqual(polygonedSampleTokenList.version)
30
+ expect(
31
+ tokenList?.tokens.map((t) => [t.address, t.chainId, t.extensions])
32
+ ).toEqual(
33
+ // ignores other metadata
34
+ optimizedSampleTokenList.tokens.map((t) => [
35
+ t.address,
36
+ t.chainId,
37
+ t.extensions,
38
+ ])
39
+ )
22
40
  })
23
41
 
24
42
  it('outputs arbitrum list correctly', async () => {
43
+ mockArbitrumProvider()
25
44
  const tokenList = await chainifyTokenList(
26
45
  ChainId.ARBITRUM_ONE,
27
46
  sampleL1TokenList
@@ -129,8 +148,8 @@ describe(mergeTokenLists, () => {
129
148
  },
130
149
  [ChainId.ARBITRUM_ONE]: {
131
150
  tokenAddress: DAI_ARBITRUM_ONE.address,
132
- destBridgeAddress: arbBridgeL2Address,
133
- originBridgeAddress: arbBridgeL1Address,
151
+ // destBridgeAddress: arbBridgeL2Address,
152
+ // originBridgeAddress: arbBridgeL1Address,
134
153
  },
135
154
  },
136
155
  },
@@ -151,8 +170,8 @@ describe(mergeTokenLists, () => {
151
170
  bridgeInfo: {
152
171
  [ChainId.MAINNET]: {
153
172
  tokenAddress: DAI.address,
154
- originBridgeAddress: arbBridgeL2Address,
155
- destBridgeAddress: arbBridgeL1Address,
173
+ // originBridgeAddress: arbBridgeL2Address,
174
+ // destBridgeAddress: arbBridgeL1Address,
156
175
  },
157
176
  },
158
177
  },
@@ -160,9 +179,9 @@ describe(mergeTokenLists, () => {
160
179
  ])
161
180
  })
162
181
  })
163
-
164
182
  describe(chainify, () => {
165
183
  it('provides bridge extensions', async () => {
184
+ mockArbitrumProvider()
166
185
  const chainified = await chainify(sampleL1TokenList)
167
186
 
168
187
  expect(chainified.tokens).toEqual([
@@ -170,13 +189,27 @@ describe(chainify, () => {
170
189
  ...Tokens[ChainId.MAINNET]!.DAI,
171
190
  extensions: {
172
191
  bridgeInfo: {
192
+ [ChainId.OPTIMISM]: {
193
+ tokenAddress: DAI_OPTIMISM.address,
194
+ },
173
195
  [ChainId.POLYGON]: {
174
196
  tokenAddress: DAI_POLYGON.address,
175
197
  },
176
198
  [ChainId.ARBITRUM_ONE]: {
177
199
  tokenAddress: DAI_ARBITRUM_ONE.address,
178
- destBridgeAddress: arbBridgeL2Address,
179
- originBridgeAddress: arbBridgeL1Address,
200
+ // destBridgeAddress: arbBridgeL2Address,
201
+ // originBridgeAddress: arbBridgeL1Address,
202
+ },
203
+ },
204
+ },
205
+ },
206
+ {
207
+ ...Tokens[ChainId.OPTIMISM]!.DAI,
208
+ name: 'Dai Stablecoin',
209
+ extensions: {
210
+ bridgeInfo: {
211
+ [ChainId.MAINNET]: {
212
+ tokenAddress: DAI.address,
180
213
  },
181
214
  },
182
215
  },
@@ -196,16 +229,25 @@ describe(chainify, () => {
196
229
  extensions: {
197
230
  bridgeInfo: {
198
231
  [ChainId.MAINNET]: {
199
- tokenAddress: DAI.address.toLowerCase(),
200
- originBridgeAddress: arbBridgeL2Address,
201
- destBridgeAddress: arbBridgeL1Address,
232
+ tokenAddress: DAI.address,
233
+ // originBridgeAddress: arbBridgeL2Address,
234
+ // destBridgeAddress: arbBridgeL1Address,
202
235
  },
203
236
  },
204
237
  },
205
- logoURI:
206
- 'https://assets.coingecko.com/coins/images/9956/thumb/4943.png?1636636734',
207
238
  name: 'Dai Stablecoin',
208
239
  },
209
240
  ])
210
241
  })
211
242
  })
243
+
244
+ // Mocking arb provider due to required infura key for network call
245
+ function mockArbitrumProvider() {
246
+ let arbTokenMap: { [key: string]: string | undefined } = {}
247
+ const DAI_ADDRESS: string = DAI.address.toLowerCase()
248
+ arbTokenMap[DAI_ADDRESS.toLowerCase()] =
249
+ DAI_ARBITRUM_ONE.address.toLowerCase()
250
+ var mockArbProvide = jest.fn()
251
+ mockArbProvide.mockImplementation(() => Promise.resolve(arbTokenMap))
252
+ ArbitrumMappingProvider.prototype.provide = mockArbProvide
253
+ }
package/src/index.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { TokenList } from '@uniswap/token-lists'
2
2
  import { cloneDeep, groupBy, merge } from 'lodash'
3
3
  import { ChainId } from './constants/chainId'
4
- import { getMappingProvider } from './providers'
4
+ import { buildList } from './providers'
5
5
  import {
6
6
  compareTokenInfos,
7
7
  getTokenList,
8
- TokenListOrFetchableTokenList
8
+ TokenListOrFetchableTokenList,
9
9
  } from './utils'
10
10
  import { verifyExtensions } from './verify'
11
11
 
@@ -49,9 +49,8 @@ export async function chainifyTokenList(
49
49
  l1TokenListOrPathOrUrl: TokenListOrFetchableTokenList
50
50
  ): Promise<TokenList> {
51
51
  try {
52
- const tokenList = await getMappingProvider(chainId).provide(
53
- await getTokenList(l1TokenListOrPathOrUrl)
54
- )
52
+ const l1TokenList = await getTokenList(l1TokenListOrPathOrUrl)
53
+ const tokenList = await buildList(chainId, l1TokenList)
55
54
  return verifyExtensions(tokenList)
56
55
  } catch (e) {
57
56
  throw new Error(`An error occured: ${e}`)
@@ -79,7 +78,6 @@ export function mergeTokenLists(
79
78
  const merged = merge(group[0], group[1])
80
79
  if (merged.extensions?.bridgeInfo) {
81
80
  // remove reference to self-chain from merge
82
- // @ts-expect-error TokenList schema doesn't yet define objects
83
81
  delete merged.extensions.bridgeInfo[merged.chainId]
84
82
  }
85
83
  return merged
@@ -89,4 +87,4 @@ export function mergeTokenLists(
89
87
  ...primary,
90
88
  tokens: merged.sort(compareTokenInfos),
91
89
  })
92
- }
90
+ }
@@ -1,28 +1,38 @@
1
- import { TokenList } from '@uniswap/token-lists'
2
- import { generateTokenList } from '../arb-token-lists/src/lib/token_list_gen'
3
- import { compareTokenInfos } from '../utils'
4
1
  import { MappingProvider } from './MappingProvider'
2
+ import { getNetworkConfig } from '../arbitrum/instantiate_bridge'
3
+ import { getL2TokenAddressesFromL1 } from '../arbitrum/gateway'
4
+ import { TokenList } from '@uniswap/token-lists'
5
5
 
6
6
  /**
7
- * The Arbitrum team maintains an (unpublished) package to `arbify` an L1
8
- * token list.
9
- *
10
- * The provider simply invokes this package which we host as a submodule.
7
+ * This provider provides the l1->l2(Arbitrum) address mappings using the arbitrum SDK.
11
8
  */
12
-
13
9
  export class ArbitrumMappingProvider implements MappingProvider {
14
- async provide(l1TokenList: TokenList): Promise<TokenList> {
15
- const arbedTokenList = (await generateTokenList(
16
- l1TokenList,
17
- /*prevArbTokenList=*/ undefined,
18
- {
19
- includeAllL1Tokens: true,
20
- }
21
- )) as unknown as TokenList
22
-
23
- return {
24
- ...arbedTokenList,
25
- tokens: arbedTokenList.tokens.sort(compareTokenInfos),
26
- }
10
+ l1TokenList: TokenList
11
+
12
+ constructor(l1TokenList: TokenList) {
13
+ this.l1TokenList = l1TokenList
14
+ }
15
+
16
+ async provide(): Promise<{ [key: string]: string | undefined }> {
17
+ let tokens: { [key: string]: string | undefined } = {}
18
+
19
+ const { l1, l2 } = await getNetworkConfig()
20
+
21
+ let tokenAddresses = this.l1TokenList.tokens.map((token) =>
22
+ token.address.toLowerCase()
23
+ )
24
+
25
+ const l2AddressesFromL1 = await getL2TokenAddressesFromL1(
26
+ tokenAddresses,
27
+ l1.multiCaller,
28
+ l2.network.tokenBridge.l1GatewayRouter
29
+ )
30
+
31
+ tokens = tokenAddresses.reduce(
32
+ (obj, key, index) => ({ ...obj, [key]: l2AddressesFromL1[index] }),
33
+ {}
34
+ )
35
+
36
+ return tokens
27
37
  }
28
38
  }
@@ -1,5 +1,7 @@
1
- import { TokenList } from '@uniswap/token-lists'
1
+ import { PolygonMappedTokenData } from '../constants/types'
2
2
 
3
3
  export interface MappingProvider {
4
- provide(l1TokenList: TokenList): Promise<TokenList>
4
+ provide(): Promise<
5
+ PolygonMappedTokenData | { [key: string]: string | undefined }
6
+ >
5
7
  }
@@ -1,13 +1,29 @@
1
- import { TokenList } from '@uniswap/token-lists'
2
1
  import { MappingProvider } from './MappingProvider'
2
+ import { ChainId } from '../constants/chainId'
3
+ import { getTokenList } from '../utils'
4
+
5
+ const optimismTokenListURL =
6
+ 'https://raw.githubusercontent.com/' +
7
+ 'ethereum-optimism/ethereum-optimism.github.io/2138386277e4156d159615d1840882cecc398437/optimism.tokenlist.json'
3
8
 
4
9
  /**
5
- * The Optimism L2 mapping is manually maintained by the Optimism team.
10
+ * The Optimism L2 mapping (linked above) is manually maintained by the Optimism team.
6
11
  *
7
- * This provider mostly no-ops, i.e. grabs the list and returns it.
12
+ * This provider provides the l1->l2(Optimism) token mappings.
8
13
  */
9
14
  export class OptimismMappingProvider implements MappingProvider {
10
- async provide(l1TokenList: TokenList): Promise<TokenList> {
11
- return l1TokenList
15
+ async provide(): Promise<{ [key: string]: string | undefined }> {
16
+ const tokens: { [key: string]: string | undefined } = {}
17
+
18
+ let optimismTokens = await getTokenList(optimismTokenListURL)
19
+
20
+ for (const token of optimismTokens.tokens) {
21
+ if (token.chainId === ChainId.MAINNET) {
22
+ tokens[token.address.toLowerCase()] =
23
+ token?.extensions?.bridgeInfo![ChainId.OPTIMISM].tokenAddress
24
+ }
25
+ }
26
+
27
+ return tokens
12
28
  }
13
29
  }
@@ -1,127 +1,35 @@
1
- import { TokenInfo, TokenList } from '@uniswap/token-lists'
2
1
  import axios from 'axios'
3
- import { compareTokenInfos } from '../utils'
4
2
  import { MappingProvider } from './MappingProvider'
3
+ import { PolygonMappedTokenData } from '../constants/types'
5
4
 
6
- interface PolygonMappedToken {
7
- chainId: number
8
- child_address_passed_by_user: boolean
9
- child_token: string
10
- count: number
11
- created_at: string
12
- decimals: number
13
- deleted: boolean
14
- id: number
15
- map_type: 'POS'
16
- mintable: boolean
17
- name: string
18
- new_child_token: string
19
- new_mintable: boolean
20
- owner: string
21
- reason: string
22
- reason_for_remapping: string
23
- remapping_allowed: boolean
24
- remapping_request_submitted: boolean
25
- remapping_verified: boolean
26
- root_token: string
27
- status: number
28
- symbol: string
29
- token_type: string // ERC20
30
- updated_at: string
31
- uri: string
32
- }
33
-
34
- type PolygonMappedTokenData = { [key: string]: PolygonMappedToken }
5
+ const url = 'https://tokenmapper.api.matic.today/api/v1/mapping?'
6
+ const params = 'map_type=[%22POS%22]&chain_id=137&limit=200&offset='
35
7
 
36
8
  /**
37
9
  * The Polygon team manually maintains the mapping via user submissions at
38
10
  * https://mapper.polygon.technology.
11
+ *
12
+ * This provider provides the l1->l2(Polygon) token mappings.
39
13
  */
40
14
  export class PolygonMappingProvider implements MappingProvider {
41
- async provide(l1TokenList: TokenList): Promise<TokenList> {
42
- const polygonTokens = await fetchPolygonMappedTokens()
43
-
44
- const mappedTokens = []
45
- for (const rootToken of l1TokenList.tokens) {
46
- const childToken = polygonTokens[rootToken.address.toLowerCase()]
47
- const childTokenValid = Boolean(childToken && !childToken.deleted)
48
-
49
- // build extension info if available
50
- const toRootExtensions = childTokenValid
51
- ? {
52
- extensions: {
53
- bridgeInfo: {
54
- [rootToken.chainId]: {
55
- tokenAddress: childToken.root_token,
56
- },
57
- },
58
- },
59
- }
60
- : {}
61
- const toChildExtensions = childTokenValid
62
- ? {
63
- extensions: {
64
- bridgeInfo: {
65
- [childToken.chainId]: {
66
- tokenAddress: childToken.child_token,
67
- },
68
- },
69
- },
70
- }
71
- : {}
72
-
73
- const rootTokenInfo: TokenInfo = {
74
- ...rootToken,
75
- ...toChildExtensions,
76
- } as unknown as TokenInfo
77
-
78
- const childTokenInfo: TokenInfo = {
79
- ...rootToken,
80
- chainId: childToken.chainId,
81
- name: childToken.name ?? rootToken.name,
82
- symbol: childToken.symbol ?? rootToken.symbol,
83
- address: childToken.child_token,
84
- ...toRootExtensions,
85
- } as unknown as TokenInfo
86
-
87
- mappedTokens.push(rootTokenInfo)
88
- mappedTokens.push(childTokenInfo)
89
- }
90
-
91
- const tokenList = {
92
- name: `Polygon ${l1TokenList.name}`,
93
- timestamp: new Date().toISOString(),
94
- version: l1TokenList.version,
95
- tokens: mappedTokens.sort(compareTokenInfos),
96
- }
97
-
98
- return tokenList
99
- }
100
- }
101
-
102
- const url = 'https://tokenmapper.api.matic.today/api/v1/mapping?'
103
- const params = 'map_type=[%22POS%22]&chain_id=137&limit=200&offset='
104
-
105
- async function fetchPolygonMappedTokens(): Promise<PolygonMappedTokenData> {
106
- let offset = 0
107
- const tokens: PolygonMappedTokenData = {}
108
-
109
- while (true) {
110
- const response = await axios.get(`${url}${params}${offset}`)
111
-
112
- if (response.data.message === 'success') {
113
- for (const token of response.data.data.mapping) {
114
- tokens[token.root_token.toLowerCase()] = token
115
- }
116
-
117
- if (response.data.data.has_next_page === true) {
118
- offset += 200
119
- continue
15
+ async provide(): Promise<PolygonMappedTokenData> {
16
+ let offset = 0
17
+ const tokens: PolygonMappedTokenData = {}
18
+ while (true) {
19
+ const response = await axios.get(`${url}${params}${offset}`)
20
+
21
+ if (response.data.message === 'success') {
22
+ for (const token of response.data.data.mapping) {
23
+ tokens[token.root_token.toLowerCase()] = token
24
+ }
25
+
26
+ if (response.data.data.has_next_page === true) {
27
+ offset += 200
28
+ continue
29
+ }
120
30
  }
31
+ break
121
32
  }
122
-
123
- break
33
+ return tokens
124
34
  }
125
-
126
- return tokens
127
35
  }
@@ -2,11 +2,91 @@ import { ChainId } from '../constants/chainId'
2
2
  import { ArbitrumMappingProvider } from './ArbitrumMappingProvider'
3
3
  import { OptimismMappingProvider } from './OptimismMappingProvider'
4
4
  import { PolygonMappingProvider } from './PolygonMappingProvider'
5
+ import { TokenInfo, TokenList } from '@uniswap/token-lists'
6
+ import { compareTokenInfos } from '../utils'
7
+ import { ethers } from 'ethers'
5
8
 
6
- export function getMappingProvider(chainId: ChainId) {
9
+ export async function buildList(
10
+ chainId: ChainId,
11
+ l1TokenList: TokenList
12
+ ): Promise<TokenList> {
13
+ const tokenAddressMap = await getMappingProvider(
14
+ chainId,
15
+ l1TokenList
16
+ ).provide()
17
+ const mappedTokens = []
18
+ for (const rootToken of l1TokenList.tokens) {
19
+ const childToken = tokenAddressMap[rootToken.address.toLowerCase()]
20
+ const childTokenValid = Boolean(
21
+ childToken &&
22
+ (typeof childToken === 'object' ? !childToken.deleted : true)
23
+ )
24
+
25
+ if (rootToken.chainId === ChainId.MAINNET) {
26
+ // build extension info if available
27
+ const toRootExtensions = childTokenValid
28
+ ? {
29
+ extensions: {
30
+ bridgeInfo: {
31
+ [rootToken.chainId]: {
32
+ tokenAddress: ethers.utils.getAddress(rootToken.address),
33
+ },
34
+ },
35
+ },
36
+ }
37
+ : {}
38
+
39
+ const toChildExtensions = childTokenValid
40
+ ? {
41
+ extensions: {
42
+ bridgeInfo: {
43
+ [chainId]: {
44
+ tokenAddress: ethers.utils.getAddress(
45
+ typeof childToken === 'object'
46
+ ? childToken.child_token
47
+ : childToken!
48
+ ),
49
+ },
50
+ },
51
+ },
52
+ }
53
+ : {}
54
+
55
+ const rootTokenInfo: TokenInfo = {
56
+ ...rootToken,
57
+ ...toChildExtensions,
58
+ } as unknown as TokenInfo
59
+
60
+ if (childTokenValid) {
61
+ const childTokenInfo: TokenInfo = {
62
+ ...rootToken,
63
+ chainId: chainId,
64
+ address: ethers.utils.getAddress(
65
+ typeof childToken === 'object'
66
+ ? childToken.child_token
67
+ : childToken!
68
+ ),
69
+ ...toRootExtensions,
70
+ } as unknown as TokenInfo
71
+ mappedTokens.push(childTokenInfo)
72
+ }
73
+ mappedTokens.push(rootTokenInfo)
74
+ }
75
+ }
76
+ const tokenList = {
77
+ name: `(ChainId: ${chainId}) ${l1TokenList.name}`,
78
+ timestamp: new Date().toISOString(),
79
+ version: l1TokenList.version,
80
+ tokens: mappedTokens.sort(compareTokenInfos),
81
+ }
82
+
83
+ return tokenList
84
+ }
85
+
86
+ function getMappingProvider(chainId: ChainId, l1TokenList: TokenList) {
7
87
  switch (chainId) {
8
88
  case ChainId.ARBITRUM_ONE:
9
- return new ArbitrumMappingProvider()
89
+ return new ArbitrumMappingProvider(l1TokenList)
10
90
  case ChainId.OPTIMISM:
11
91
  return new OptimismMappingProvider()
12
92
  case ChainId.POLYGON: