@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.
- package/dist/constants/chainId.d.ts +2 -1
- package/dist/providers/SoneiumMappingProvider.d.ts +5 -0
- package/dist/token-list-bridge-utils.cjs.development.js +87 -9
- 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 +87 -9
- package/dist/token-list-bridge-utils.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/constants/chainId.ts +2 -0
- package/src/index.ts +1 -0
- package/src/local_mappings/soneium.json +14 -0
- package/src/providers/ArbitrumMappingProvider.test.ts +123 -0
- package/src/providers/ArbitrumMappingProvider.ts +16 -6
- package/src/providers/SoneiumMappingProvider.ts +11 -0
- package/src/providers/index.ts +4 -0
- package/src/utils.ts +2 -0
|
@@ -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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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]:
|
|
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
|
+
}
|
package/src/providers/index.ts
CHANGED
|
@@ -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')
|