@uniswap/token-list-bridge-utils 2.7.0 → 2.9.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.
@@ -0,0 +1,123 @@
1
+ import { ArbitrumMappingProvider } from './ArbitrumMappingProvider'
2
+ import { getL2TokenAddressesFromL1 } from '../arbitrum/gateway'
3
+ import { getNetworkConfig } from '../arbitrum/instantiate_bridge'
4
+ import { TokenList } from '@uniswap/token-lists'
5
+
6
+ jest.mock('../arbitrum/gateway')
7
+ jest.mock('../arbitrum/instantiate_bridge')
8
+
9
+ describe('ArbitrumMappingProvider', () => {
10
+ const mockL1TokenList: TokenList = {
11
+ name: 'Test Token List',
12
+ timestamp: '2024-01-01T00:00:00.000Z',
13
+ version: { major: 1, minor: 0, patch: 0 },
14
+ tokens: [
15
+ {
16
+ address: '0x1234',
17
+ chainId: 1,
18
+ decimals: 18,
19
+ name: 'Token1',
20
+ symbol: 'TK1',
21
+ },
22
+ {
23
+ address: '0x5678',
24
+ chainId: 1,
25
+ decimals: 18,
26
+ name: 'Token2',
27
+ symbol: 'TK2',
28
+ },
29
+ {
30
+ address: '0x9abc',
31
+ chainId: 1,
32
+ decimals: 18,
33
+ name: 'Token3',
34
+ symbol: 'TK3',
35
+ },
36
+ ],
37
+ }
38
+
39
+ const mockNetworkConfig = {
40
+ l1: {
41
+ multiCaller: 'mockMultiCaller',
42
+ },
43
+ l2: {
44
+ network: {
45
+ tokenBridge: {
46
+ l1GatewayRouter: '0xgatewayAddress',
47
+ },
48
+ },
49
+ },
50
+ }
51
+
52
+ beforeEach(() => {
53
+ jest.clearAllMocks()
54
+ ;(getNetworkConfig as jest.Mock).mockResolvedValue(mockNetworkConfig)
55
+ })
56
+
57
+ it('should correctly map L1 tokens to L2 addresses in batches', async () => {
58
+ const mockL2Addresses = ['0x1234L2', '0x5678L2', '0x9abcL2']
59
+ ;(getL2TokenAddressesFromL1 as jest.Mock).mockResolvedValue(mockL2Addresses)
60
+
61
+ const provider = new ArbitrumMappingProvider(mockL1TokenList)
62
+ const result = await provider.provide()
63
+
64
+ expect(result).toEqual({
65
+ '0x1234': '0x1234L2',
66
+ '0x5678': '0x5678L2',
67
+ '0x9abc': '0x9abcL2',
68
+ })
69
+
70
+ expect(getL2TokenAddressesFromL1).toHaveBeenCalledWith(
71
+ ['0x1234', '0x5678', '0x9abc'].map((addr) => addr.toLowerCase()),
72
+ 'mockMultiCaller',
73
+ '0xgatewayAddress'
74
+ )
75
+ })
76
+
77
+ it('should handle undefined L2 addresses correctly', async () => {
78
+ const mockL2Addresses = ['0x1234L2', undefined, '0x9abcL2']
79
+ ;(getL2TokenAddressesFromL1 as jest.Mock).mockImplementation(
80
+ (addresses) => {
81
+ // Return only the defined addresses from our mock data
82
+ return mockL2Addresses.filter((addr) => addr !== undefined)
83
+ }
84
+ )
85
+
86
+ const provider = new ArbitrumMappingProvider(mockL1TokenList)
87
+ const result = await provider.provide()
88
+
89
+ // Our implementation filters out undefined values before adding to batches array,
90
+ // so the indexes will shift. The final mapping will have undefined for any
91
+ // addresses that don't have a corresponding L2 address in order
92
+ expect(result).toEqual({
93
+ '0x1234': '0x1234L2',
94
+ '0x5678': '0x9abcL2', // Gets the next available L2 address
95
+ '0x9abc': undefined, // No more L2 addresses available
96
+ })
97
+ })
98
+
99
+ it('should process tokens in batches of 100', async () => {
100
+ // Create a token list with 150 tokens
101
+ const largeTokenList: TokenList = {
102
+ ...mockL1TokenList,
103
+ tokens: Array.from({ length: 150 }, (_, i) => ({
104
+ address: `0x${i}`,
105
+ chainId: 1,
106
+ decimals: 18,
107
+ name: `Token${i}`,
108
+ symbol: `TK${i}`,
109
+ })),
110
+ }
111
+
112
+ const provider = new ArbitrumMappingProvider(largeTokenList)
113
+ await provider.provide()
114
+
115
+ // Verify that getL2TokenAddressesFromL1 was called twice
116
+ // Once with 100 tokens and once with 50 tokens
117
+ expect(getL2TokenAddressesFromL1).toHaveBeenCalledTimes(2)
118
+ const firstCall = (getL2TokenAddressesFromL1 as jest.Mock).mock.calls[0][0]
119
+ const secondCall = (getL2TokenAddressesFromL1 as jest.Mock).mock.calls[1][0]
120
+ expect(firstCall.length).toBe(100)
121
+ expect(secondCall.length).toBe(50)
122
+ })
123
+ })
@@ -23,14 +23,24 @@ export class ArbitrumMappingProvider implements MappingProvider {
23
23
  token.address.toLowerCase()
24
24
  )
25
25
 
26
- const l2AddressesFromL1 = await getL2TokenAddressesFromL1(
27
- tokenAddresses,
28
- l1.multiCaller,
29
- l2.network.tokenBridge.l1GatewayRouter
30
- )
26
+ // batching calls to avoid rpc response size limits
27
+ const batchSize = 100
28
+ const batches: string[] = []
29
+ for (let i = 0; i < tokenAddresses.length; i += batchSize) {
30
+ const batch = tokenAddresses.slice(i, i + batchSize)
31
+ const batchResults = await getL2TokenAddressesFromL1(
32
+ batch,
33
+ l1.multiCaller,
34
+ l2.network.tokenBridge.l1GatewayRouter
35
+ )
36
+ const filteredResults = batchResults.filter(
37
+ (addr): addr is string => addr !== undefined
38
+ )
39
+ batches.push(...filteredResults)
40
+ }
31
41
 
32
42
  tokens = tokenAddresses.reduce(
33
- (obj, key, index) => ({ ...obj, [key]: l2AddressesFromL1[index] }),
43
+ (obj, key, index) => ({ ...obj, [key]: batches[index] }),
34
44
  {}
35
45
  )
36
46
 
@@ -0,0 +1,11 @@
1
+ import { MappingProvider } from './MappingProvider'
2
+ import { MappedTokenData } from '../constants/types'
3
+ import soneiumMappings from '../local_mappings/soneium.json'
4
+
5
+ // we use a local source of mappings for soneium
6
+ export class SoneiumMappingProvider implements MappingProvider {
7
+ async provide(): Promise<MappedTokenData> {
8
+ const tokens = soneiumMappings as MappedTokenData
9
+ return tokens
10
+ }
11
+ }
@@ -24,6 +24,7 @@ import {
24
24
  import { AvalancheMappingProvider } from './AvalancheMappingProvider'
25
25
  import { BaseMappingProvider } from './BaseMappingProvider'
26
26
  import { CeloMappingProvider } from './CeloMappingProvider'
27
+ import { SoneiumMappingProvider } from './SoneiumMappingProvider'
27
28
 
28
29
  const web3 = new Web3()
29
30
 
@@ -37,6 +38,7 @@ const CHAINS_WITH_MAPPING_PROVIDERS = [
37
38
  ChainId.CELO,
38
39
  ChainId.BASE,
39
40
  ChainId.UNICHAIN,
41
+ ChainId.SONEIUM,
40
42
  ]
41
43
 
42
44
  export async function buildList(
@@ -162,6 +164,8 @@ function getMappingProvider(chainId: ChainId, l1TokenList: TokenList) {
162
164
  return new BaseMappingProvider()
163
165
  case ChainId.UNICHAIN:
164
166
  return new UnichainMappingProvider()
167
+ case ChainId.SONEIUM:
168
+ return new SoneiumMappingProvider()
165
169
  default:
166
170
  throw new Error(`Chain ${chainId} not supported for fetching mappings.`)
167
171
  }
package/src/utils.ts CHANGED
@@ -118,6 +118,8 @@ export function getRpcUrl(chainId: ChainId): string {
118
118
  return 'https://alfajores-forno.celo-testnet.org/'
119
119
  case ChainId.BASE:
120
120
  return 'https://mainnet.base.org'
121
+ case ChainId.SONEIUM:
122
+ return 'https://soneium.drpc.org'
121
123
  default:
122
124
  }
123
125
  throw new Error('Unsupported ChainId')