@gibs/bridge-sdk 1.10.1 → 1.12.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/package.json +12 -5
- package/src/abis.ts +3 -70
- package/src/chain-info.test.ts +968 -0
- package/src/chain-info.ts +161 -127
- package/src/chains.test.ts +123 -0
- package/src/chains.ts +5 -5
- package/src/config.test.ts +679 -0
- package/src/config.ts +138 -118
- package/src/fee-type.test.ts +45 -0
- package/src/fee-type.ts +2 -2
- package/src/image-links.test.ts +160 -0
- package/src/image-links.ts +20 -16
- package/src/index.ts +8 -8
- package/src/settings.test.ts +2754 -0
- package/src/settings.ts +325 -348
- package/src/types.ts +25 -25
- package/tsconfig.json +2 -1
- package/vitest.config.ts +13 -0
- package/dist/src/abis.d.ts +0 -384
- package/dist/src/abis.js +0 -68
- package/dist/src/chain-info.d.ts +0 -130
- package/dist/src/chain-info.js +0 -350
- package/dist/src/chains.d.ts +0 -6
- package/dist/src/chains.js +0 -86
- package/dist/src/config.d.ts +0 -136
- package/dist/src/config.js +0 -386
- package/dist/src/fee-type.d.ts +0 -10
- package/dist/src/fee-type.js +0 -9
- package/dist/src/image-links.d.ts +0 -41
- package/dist/src/image-links.js +0 -45
- package/dist/src/index.d.ts +0 -8
- package/dist/src/index.js +0 -8
- package/dist/src/settings.d.ts +0 -357
- package/dist/src/settings.js +0 -642
- package/dist/src/types.d.ts +0 -44
- package/dist/src/types.js +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,968 @@
|
|
|
1
|
+
import type { Hex } from 'viem';
|
|
2
|
+
import { zeroAddress } from 'viem';
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import {
|
|
5
|
+
chainMulticall,
|
|
6
|
+
fetchPriceCorrective,
|
|
7
|
+
links,
|
|
8
|
+
loadBridgeFees,
|
|
9
|
+
minBridgeAmountIn,
|
|
10
|
+
nativeSymbol,
|
|
11
|
+
readAmountOut,
|
|
12
|
+
tokenBridgeInfo,
|
|
13
|
+
} from './chain-info';
|
|
14
|
+
import { Chains, nativeAssetOut, Providers, pathway } from './config';
|
|
15
|
+
|
|
16
|
+
// Mock viem and multicall
|
|
17
|
+
vi.mock('viem', async () => {
|
|
18
|
+
const actual = await vi.importActual<typeof import('viem')>('viem');
|
|
19
|
+
return {
|
|
20
|
+
...actual,
|
|
21
|
+
getContract: vi.fn(() => ({
|
|
22
|
+
read: {
|
|
23
|
+
mediatorContractOnOtherSide: vi.fn(),
|
|
24
|
+
getBridgeMode: vi.fn(),
|
|
25
|
+
minPerTx: vi.fn(),
|
|
26
|
+
getFee: vi.fn(),
|
|
27
|
+
FOREIGN_TO_HOME_FEE: vi.fn(),
|
|
28
|
+
HOME_TO_FOREIGN_FEE: vi.fn(),
|
|
29
|
+
calculateFee: vi.fn(),
|
|
30
|
+
getAmountToBurn: vi.fn(),
|
|
31
|
+
priceCorrective: vi.fn(),
|
|
32
|
+
},
|
|
33
|
+
})),
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
vi.mock('@gibs/common/multicall', () => ({
|
|
38
|
+
multicallRead: vi.fn(),
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
describe('chain-info', () => {
|
|
42
|
+
describe('nativeSymbol', () => {
|
|
43
|
+
it('should return empty string for null asset', () => {
|
|
44
|
+
expect(nativeSymbol(null)).toBe('');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should return symbol when not unwrapping', () => {
|
|
48
|
+
const asset = {
|
|
49
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
50
|
+
symbol: 'USDC',
|
|
51
|
+
chainId: 1,
|
|
52
|
+
};
|
|
53
|
+
expect(nativeSymbol(asset, false)).toBe('USDC');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should return symbol without first character when unwrapping native asset', () => {
|
|
57
|
+
const wethAddress = nativeAssetOut[Chains.ETH];
|
|
58
|
+
const asset = {
|
|
59
|
+
address: wethAddress,
|
|
60
|
+
symbol: 'WETH',
|
|
61
|
+
chainId: 1,
|
|
62
|
+
};
|
|
63
|
+
expect(nativeSymbol(asset, true)).toBe('ETH');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should not strip character if unwrap is true but not a native asset', () => {
|
|
67
|
+
const asset = {
|
|
68
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
69
|
+
symbol: 'USDC',
|
|
70
|
+
chainId: 1,
|
|
71
|
+
};
|
|
72
|
+
expect(nativeSymbol(asset, true)).toBe('USDC');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should handle WPLS unwrapping', () => {
|
|
76
|
+
const wplsAddress = nativeAssetOut[Chains.PLS];
|
|
77
|
+
const asset = {
|
|
78
|
+
address: wplsAddress,
|
|
79
|
+
symbol: 'WPLS',
|
|
80
|
+
chainId: parseInt(Chains.PLS, 16),
|
|
81
|
+
};
|
|
82
|
+
expect(nativeSymbol(asset, true)).toBe('PLS');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should handle WBNB unwrapping', () => {
|
|
86
|
+
const wbnbAddress = nativeAssetOut[Chains.BNB];
|
|
87
|
+
const asset = {
|
|
88
|
+
address: wbnbAddress,
|
|
89
|
+
symbol: 'WBNB',
|
|
90
|
+
chainId: parseInt(Chains.BNB, 16),
|
|
91
|
+
};
|
|
92
|
+
expect(nativeSymbol(asset, true)).toBe('BNB');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should return full symbol when unwrap is false', () => {
|
|
96
|
+
const wethAddress = nativeAssetOut[Chains.ETH];
|
|
97
|
+
const asset = {
|
|
98
|
+
address: wethAddress,
|
|
99
|
+
symbol: 'WETH',
|
|
100
|
+
chainId: 1,
|
|
101
|
+
};
|
|
102
|
+
expect(nativeSymbol(asset, false)).toBe('WETH');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should handle empty symbol', () => {
|
|
106
|
+
const asset = {
|
|
107
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
108
|
+
symbol: '',
|
|
109
|
+
chainId: 1,
|
|
110
|
+
};
|
|
111
|
+
expect(nativeSymbol(asset, false)).toBe('');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should default unwrap to false when not provided', () => {
|
|
115
|
+
const asset = {
|
|
116
|
+
address: nativeAssetOut[Chains.ETH],
|
|
117
|
+
symbol: 'WETH',
|
|
118
|
+
chainId: 1,
|
|
119
|
+
};
|
|
120
|
+
// Without unwrap parameter, should return full symbol
|
|
121
|
+
expect(nativeSymbol(asset)).toBe('WETH');
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe('links', () => {
|
|
126
|
+
let mockClient: any;
|
|
127
|
+
|
|
128
|
+
beforeEach(() => {
|
|
129
|
+
mockClient = { chain: { id: 1 } };
|
|
130
|
+
vi.clearAllMocks();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should fetch link info for a token', async () => {
|
|
134
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
135
|
+
(multicallRead as any).mockResolvedValue(['0xBridgedToken' as Hex, '0xNativeToken' as Hex]);
|
|
136
|
+
|
|
137
|
+
const result = await links({
|
|
138
|
+
chainId: 1,
|
|
139
|
+
target: '0xBridgeAddress' as Hex,
|
|
140
|
+
address: '0xTokenAddress' as Hex,
|
|
141
|
+
client: mockClient,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
expect(result).toBeDefined();
|
|
145
|
+
expect(Array.isArray(result)).toBe(true);
|
|
146
|
+
expect(result[0]).toBe('0xBridgedToken');
|
|
147
|
+
expect(result[1]).toBe('0xNativeToken');
|
|
148
|
+
expect(multicallRead).toHaveBeenCalled();
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe('tokenBridgeInfo', () => {
|
|
153
|
+
let mockFromClient: any;
|
|
154
|
+
let mockToClient: any;
|
|
155
|
+
|
|
156
|
+
beforeEach(() => {
|
|
157
|
+
mockFromClient = { chain: { id: 1 } };
|
|
158
|
+
mockToClient = { chain: { id: 369 } };
|
|
159
|
+
vi.clearAllMocks();
|
|
160
|
+
// Clear memoization cache for links function
|
|
161
|
+
(links as any).cache = new Map();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should return null when assetIn is null', async () => {
|
|
165
|
+
const result = await tokenBridgeInfo({
|
|
166
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
167
|
+
assetIn: null,
|
|
168
|
+
isProd: true,
|
|
169
|
+
fromChainClient: mockFromClient,
|
|
170
|
+
toChainClient: mockToClient,
|
|
171
|
+
});
|
|
172
|
+
expect(result).toBeNull();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should fetch token bridge info successfully', async () => {
|
|
176
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
177
|
+
(multicallRead as any).mockResolvedValue([['0xForeignToken' as Hex, '0xNativeToken' as Hex]]);
|
|
178
|
+
|
|
179
|
+
const assetIn = {
|
|
180
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
181
|
+
symbol: 'USDC',
|
|
182
|
+
decimals: 6,
|
|
183
|
+
name: 'USD Coin',
|
|
184
|
+
chainId: 1,
|
|
185
|
+
logoURI: null,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const result = await tokenBridgeInfo({
|
|
189
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
190
|
+
assetIn,
|
|
191
|
+
isProd: true,
|
|
192
|
+
fromChainClient: mockFromClient,
|
|
193
|
+
toChainClient: mockToClient,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(result).toBeDefined();
|
|
197
|
+
expect(result?.assetInAddress).toBeDefined();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should handle toBridged path when toBridged is not zero', async () => {
|
|
201
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
202
|
+
const toBridgedAddress = '0x1234567890123456789012345678901234567890' as Hex;
|
|
203
|
+
(multicallRead as any).mockReset();
|
|
204
|
+
(multicallRead as any)
|
|
205
|
+
.mockResolvedValueOnce([toBridgedAddress, zeroAddress]) // First links() call - toMappings
|
|
206
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]); // Second links() call - fromMappings
|
|
207
|
+
|
|
208
|
+
const assetIn = {
|
|
209
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as Hex,
|
|
210
|
+
symbol: 'USDC',
|
|
211
|
+
decimals: 6,
|
|
212
|
+
name: 'USD Coin',
|
|
213
|
+
chainId: 1,
|
|
214
|
+
logoURI: null,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const result = await tokenBridgeInfo({
|
|
218
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
219
|
+
assetIn,
|
|
220
|
+
isProd: true,
|
|
221
|
+
fromChainClient: mockFromClient,
|
|
222
|
+
toChainClient: mockToClient,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
expect(result).toBeDefined();
|
|
226
|
+
expect(result?.assetOutAddress).toBe(toBridgedAddress);
|
|
227
|
+
expect(result?.originationChainId).toBe(Chains.PLS);
|
|
228
|
+
expect(result?.toHome).toBeDefined();
|
|
229
|
+
expect(result?.toHome?.home).toBe(toBridgedAddress);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should handle toNative path when toNative is not zero', async () => {
|
|
233
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
234
|
+
const toNativeAddress = '0x2345678901234567890123456789012345678901' as Hex;
|
|
235
|
+
(multicallRead as any).mockReset();
|
|
236
|
+
(multicallRead as any)
|
|
237
|
+
.mockResolvedValueOnce([zeroAddress, toNativeAddress]) // First links() call - toMappings
|
|
238
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]); // Second links() call - fromMappings
|
|
239
|
+
|
|
240
|
+
const assetIn = {
|
|
241
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as Hex,
|
|
242
|
+
symbol: 'USDC',
|
|
243
|
+
decimals: 6,
|
|
244
|
+
name: 'USD Coin',
|
|
245
|
+
chainId: 1,
|
|
246
|
+
logoURI: null,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const result = await tokenBridgeInfo({
|
|
250
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
251
|
+
assetIn,
|
|
252
|
+
isProd: true,
|
|
253
|
+
fromChainClient: mockFromClient,
|
|
254
|
+
toChainClient: mockToClient,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
expect(result).toBeDefined();
|
|
258
|
+
expect(result?.assetOutAddress).toBe(toNativeAddress);
|
|
259
|
+
expect(result?.originationChainId).toBe(Chains.ETH);
|
|
260
|
+
expect(result?.toForeign).toBeDefined();
|
|
261
|
+
expect(result?.toForeign?.home).toBe(toNativeAddress);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('should handle fromNative path when fromNative is not zero', async () => {
|
|
265
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
266
|
+
const fromNativeAddress = '0x3456789012345678901234567890123456789012' as Hex;
|
|
267
|
+
(multicallRead as any).mockReset();
|
|
268
|
+
(multicallRead as any)
|
|
269
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]) // First links() call - toMappings
|
|
270
|
+
.mockResolvedValueOnce([zeroAddress, fromNativeAddress]); // Second links() call - fromMappings
|
|
271
|
+
|
|
272
|
+
const assetIn = {
|
|
273
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as Hex,
|
|
274
|
+
symbol: 'USDC',
|
|
275
|
+
decimals: 6,
|
|
276
|
+
name: 'USD Coin',
|
|
277
|
+
chainId: 1,
|
|
278
|
+
logoURI: null,
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const result = await tokenBridgeInfo({
|
|
282
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
283
|
+
assetIn,
|
|
284
|
+
isProd: true,
|
|
285
|
+
fromChainClient: mockFromClient,
|
|
286
|
+
toChainClient: mockToClient,
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
expect(result).toBeDefined();
|
|
290
|
+
expect(result?.assetOutAddress).toBe(fromNativeAddress);
|
|
291
|
+
expect(result?.originationChainId).toBe(Chains.ETH);
|
|
292
|
+
expect(result?.toHome).toBeDefined();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should handle fromBridged path when fromBridged is not zero', async () => {
|
|
296
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
297
|
+
const fromBridgedAddress = '0x4567890123456789012345678901234567890123' as Hex;
|
|
298
|
+
(multicallRead as any).mockReset();
|
|
299
|
+
(multicallRead as any)
|
|
300
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]) // First links() call - toMappings
|
|
301
|
+
.mockResolvedValueOnce([fromBridgedAddress, zeroAddress]); // Second links() call - fromMappings
|
|
302
|
+
|
|
303
|
+
const assetIn = {
|
|
304
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as Hex,
|
|
305
|
+
symbol: 'USDC',
|
|
306
|
+
decimals: 6,
|
|
307
|
+
name: 'USD Coin',
|
|
308
|
+
chainId: 1,
|
|
309
|
+
logoURI: null,
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
const result = await tokenBridgeInfo({
|
|
313
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
314
|
+
assetIn,
|
|
315
|
+
isProd: true,
|
|
316
|
+
fromChainClient: mockFromClient,
|
|
317
|
+
toChainClient: mockToClient,
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
expect(result).toBeDefined();
|
|
321
|
+
expect(result?.assetOutAddress).toBe(fromBridgedAddress);
|
|
322
|
+
expect(result?.originationChainId).toBe(Chains.PLS);
|
|
323
|
+
expect(result?.toForeign).toBeDefined();
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should handle not-yet-bridged token with toHome pathway', async () => {
|
|
327
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
328
|
+
(multicallRead as any).mockReset();
|
|
329
|
+
(multicallRead as any)
|
|
330
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]) // First links() call - toMappings
|
|
331
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]); // Second links() call - fromMappings
|
|
332
|
+
|
|
333
|
+
const assetIn = {
|
|
334
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as Hex,
|
|
335
|
+
symbol: 'USDC',
|
|
336
|
+
decimals: 6,
|
|
337
|
+
name: 'USD Coin',
|
|
338
|
+
chainId: 1,
|
|
339
|
+
logoURI: null,
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// Create pathway with toHome = true
|
|
343
|
+
const bridgePathway = pathway([Providers.PULSECHAIN, Chains.ETH, Chains.PLS], true);
|
|
344
|
+
expect(bridgePathway?.toHome).toBe(true);
|
|
345
|
+
|
|
346
|
+
const result = await tokenBridgeInfo({
|
|
347
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.ETH, Chains.PLS],
|
|
348
|
+
assetIn,
|
|
349
|
+
isProd: true,
|
|
350
|
+
fromChainClient: mockFromClient,
|
|
351
|
+
toChainClient: mockToClient,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
expect(result).toBeDefined();
|
|
355
|
+
expect(result?.assetOutAddress).toBeNull();
|
|
356
|
+
expect(result?.toHome).toBeDefined();
|
|
357
|
+
expect(result?.toHome?.home).toBeNull();
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('should handle not-yet-bridged token with toForeign pathway', async () => {
|
|
361
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
362
|
+
(multicallRead as any).mockReset();
|
|
363
|
+
(multicallRead as any)
|
|
364
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]) // First links() call - toMappings
|
|
365
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]); // Second links() call - fromMappings
|
|
366
|
+
|
|
367
|
+
const assetIn = {
|
|
368
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as Hex,
|
|
369
|
+
symbol: 'USDC',
|
|
370
|
+
decimals: 6,
|
|
371
|
+
name: 'USD Coin',
|
|
372
|
+
chainId: 1,
|
|
373
|
+
logoURI: null,
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
// Create pathway with toHome = false (toForeign)
|
|
377
|
+
const bridgePathway = pathway([Providers.PULSECHAIN, Chains.PLS, Chains.ETH], true);
|
|
378
|
+
expect(bridgePathway?.toHome).toBe(false);
|
|
379
|
+
|
|
380
|
+
const result = await tokenBridgeInfo({
|
|
381
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
382
|
+
assetIn,
|
|
383
|
+
isProd: true,
|
|
384
|
+
fromChainClient: mockFromClient,
|
|
385
|
+
toChainClient: mockToClient,
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
expect(result).toBeDefined();
|
|
389
|
+
expect(result?.assetOutAddress).toBeNull();
|
|
390
|
+
expect(result?.toForeign).toBeDefined();
|
|
391
|
+
expect(result?.toForeign?.foreign).toBeNull();
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it('should wrap native asset address to nativeAssetOut', async () => {
|
|
395
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
396
|
+
const toBridgedAddress = '0x1234567890123456789012345678901234567890' as Hex;
|
|
397
|
+
(multicallRead as any).mockReset();
|
|
398
|
+
(multicallRead as any)
|
|
399
|
+
.mockResolvedValueOnce([toBridgedAddress, zeroAddress]) // First links() call - toMappings
|
|
400
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]); // Second links() call - fromMappings
|
|
401
|
+
|
|
402
|
+
const assetIn = {
|
|
403
|
+
address: zeroAddress,
|
|
404
|
+
symbol: 'PLS',
|
|
405
|
+
decimals: 18,
|
|
406
|
+
name: 'Pulse',
|
|
407
|
+
chainId: 369,
|
|
408
|
+
logoURI: null,
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
await tokenBridgeInfo({
|
|
412
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
413
|
+
assetIn,
|
|
414
|
+
isProd: true,
|
|
415
|
+
fromChainClient: mockFromClient,
|
|
416
|
+
toChainClient: mockToClient,
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Verify that links was called with nativeAssetOut[fromChain] instead of zeroAddress
|
|
420
|
+
expect(multicallRead).toHaveBeenCalled();
|
|
421
|
+
const callArgs = (multicallRead as any).mock.calls[0][0];
|
|
422
|
+
// The target should be one of the bridge addresses, not checking the exact value here
|
|
423
|
+
expect(callArgs).toBeDefined();
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
describe('chainMulticall', () => {
|
|
428
|
+
it('should create chainMulticall helper', () => {
|
|
429
|
+
const mockClient = { chain: { id: 1 } };
|
|
430
|
+
const result = chainMulticall(mockClient as any);
|
|
431
|
+
|
|
432
|
+
expect(result).toBeDefined();
|
|
433
|
+
expect(typeof result).toBe('object');
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
describe('loadBridgeFees', () => {
|
|
438
|
+
let mockFromClient: any;
|
|
439
|
+
let mockToClient: any;
|
|
440
|
+
|
|
441
|
+
beforeEach(() => {
|
|
442
|
+
vi.clearAllMocks();
|
|
443
|
+
|
|
444
|
+
mockFromClient = {
|
|
445
|
+
chain: {
|
|
446
|
+
id: 1,
|
|
447
|
+
contracts: {
|
|
448
|
+
multicall3: { address: '0xca11bde05977b3631167028862be2a173976ca11' as Hex },
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
mockToClient = {
|
|
454
|
+
chain: {
|
|
455
|
+
id: 369,
|
|
456
|
+
contracts: {
|
|
457
|
+
multicall3: { address: '0xca11bde05977b3631167028862be2a173976ca11' as Hex },
|
|
458
|
+
},
|
|
459
|
+
},
|
|
460
|
+
};
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('should load bridge fees from "from" side fee manager', async () => {
|
|
464
|
+
const { getContract } = await import('viem');
|
|
465
|
+
|
|
466
|
+
// Mock the sequential aggregate3 calls
|
|
467
|
+
let callCount = 0;
|
|
468
|
+
const mockAggregate3 = vi.fn().mockImplementation(() => {
|
|
469
|
+
callCount++;
|
|
470
|
+
if (callCount === 1) {
|
|
471
|
+
// First call: get feeManager address
|
|
472
|
+
return Promise.resolve([
|
|
473
|
+
{
|
|
474
|
+
success: true,
|
|
475
|
+
returnData: '0x000000000000000000000000feeManager1234567890123456789012345678' as Hex,
|
|
476
|
+
},
|
|
477
|
+
]);
|
|
478
|
+
} else if (callCount === 2) {
|
|
479
|
+
// Second call: get fee keys (HOME_TO_FOREIGN_FEE, FOREIGN_TO_HOME_FEE) - must be bytes32
|
|
480
|
+
return Promise.resolve([
|
|
481
|
+
{
|
|
482
|
+
success: true,
|
|
483
|
+
returnData:
|
|
484
|
+
'0x0000000000000000000000000000000000000000000000000000000000000001' as Hex,
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
success: true,
|
|
488
|
+
returnData:
|
|
489
|
+
'0x0000000000000000000000000000000000000000000000000000000000000002' as Hex,
|
|
490
|
+
},
|
|
491
|
+
]);
|
|
492
|
+
} else {
|
|
493
|
+
// Third call: get actual fees
|
|
494
|
+
return Promise.resolve([
|
|
495
|
+
{
|
|
496
|
+
success: true,
|
|
497
|
+
returnData:
|
|
498
|
+
'0x0000000000000000000000000000000000000000000000000de0b6b3a7640000' as Hex,
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
success: true,
|
|
502
|
+
returnData:
|
|
503
|
+
'0x0000000000000000000000000000000000000000000000001bc16d674ec80000' as Hex,
|
|
504
|
+
},
|
|
505
|
+
]);
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
(getContract as any).mockReturnValue({
|
|
510
|
+
read: {
|
|
511
|
+
aggregate3: mockAggregate3,
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
const bridgePathway = {
|
|
516
|
+
...pathway([Providers.PULSECHAIN, Chains.PLS, Chains.ETH], true)!,
|
|
517
|
+
feeManager: 'from' as const,
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
const result = await loadBridgeFees({
|
|
521
|
+
pathway: bridgePathway,
|
|
522
|
+
fromChainClient: mockFromClient,
|
|
523
|
+
toChainClient: mockToClient,
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
expect(result).toBeDefined();
|
|
527
|
+
expect(result.feeManager).toBeDefined();
|
|
528
|
+
expect(result.feeH2F).toBeDefined();
|
|
529
|
+
expect(result.feeF2H).toBeDefined();
|
|
530
|
+
expect(mockAggregate3).toHaveBeenCalledTimes(3);
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it('should load bridge fees from "to" side fee manager', async () => {
|
|
534
|
+
const { getContract } = await import('viem');
|
|
535
|
+
|
|
536
|
+
let callCount = 0;
|
|
537
|
+
const mockAggregate3 = vi.fn().mockImplementation(() => {
|
|
538
|
+
callCount++;
|
|
539
|
+
if (callCount === 1) {
|
|
540
|
+
return Promise.resolve([
|
|
541
|
+
{
|
|
542
|
+
success: true,
|
|
543
|
+
returnData: '0x000000000000000000000000feeManager9876543210987654321098765432' as Hex,
|
|
544
|
+
},
|
|
545
|
+
]);
|
|
546
|
+
} else if (callCount === 2) {
|
|
547
|
+
return Promise.resolve([
|
|
548
|
+
{
|
|
549
|
+
success: true,
|
|
550
|
+
returnData:
|
|
551
|
+
'0x0000000000000000000000000000000000000000000000000000000000000001' as Hex,
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
success: true,
|
|
555
|
+
returnData:
|
|
556
|
+
'0x0000000000000000000000000000000000000000000000000000000000000002' as Hex,
|
|
557
|
+
},
|
|
558
|
+
]);
|
|
559
|
+
} else {
|
|
560
|
+
return Promise.resolve([
|
|
561
|
+
{
|
|
562
|
+
success: true,
|
|
563
|
+
returnData:
|
|
564
|
+
'0x0000000000000000000000000000000000000000000000000de0b6b3a7640000' as Hex,
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
success: true,
|
|
568
|
+
returnData:
|
|
569
|
+
'0x0000000000000000000000000000000000000000000000001bc16d674ec80000' as Hex,
|
|
570
|
+
},
|
|
571
|
+
]);
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
(getContract as any).mockReturnValue({
|
|
576
|
+
read: {
|
|
577
|
+
aggregate3: mockAggregate3,
|
|
578
|
+
},
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
const bridgePathway = {
|
|
582
|
+
...pathway([Providers.PULSECHAIN, Chains.ETH, Chains.PLS], true)!,
|
|
583
|
+
feeManager: 'to' as const,
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
const result = await loadBridgeFees({
|
|
587
|
+
pathway: bridgePathway,
|
|
588
|
+
fromChainClient: mockFromClient,
|
|
589
|
+
toChainClient: mockToClient,
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
expect(result).toBeDefined();
|
|
593
|
+
expect(mockAggregate3).toHaveBeenCalledTimes(3);
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
it('should throw error when feeManager call fails', async () => {
|
|
597
|
+
const { getContract } = await import('viem');
|
|
598
|
+
|
|
599
|
+
const mockAggregate3 = vi.fn().mockResolvedValue([
|
|
600
|
+
{
|
|
601
|
+
success: false,
|
|
602
|
+
returnData: '0x' as Hex,
|
|
603
|
+
},
|
|
604
|
+
]);
|
|
605
|
+
|
|
606
|
+
(getContract as any).mockReturnValue({
|
|
607
|
+
read: {
|
|
608
|
+
aggregate3: mockAggregate3,
|
|
609
|
+
},
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
const bridgePathway = pathway([Providers.PULSECHAIN, Chains.PLS, Chains.ETH], true)!;
|
|
613
|
+
|
|
614
|
+
await expect(
|
|
615
|
+
loadBridgeFees({
|
|
616
|
+
pathway: bridgePathway,
|
|
617
|
+
fromChainClient: mockFromClient,
|
|
618
|
+
toChainClient: mockToClient,
|
|
619
|
+
}),
|
|
620
|
+
).rejects.toThrow('unable to load feeManager');
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
it('should throw error when feeManager returns empty data', async () => {
|
|
624
|
+
const { getContract } = await import('viem');
|
|
625
|
+
|
|
626
|
+
const mockAggregate3 = vi.fn().mockResolvedValue([
|
|
627
|
+
{
|
|
628
|
+
success: true,
|
|
629
|
+
returnData: '0x' as Hex,
|
|
630
|
+
},
|
|
631
|
+
]);
|
|
632
|
+
|
|
633
|
+
(getContract as any).mockReturnValue({
|
|
634
|
+
read: {
|
|
635
|
+
aggregate3: mockAggregate3,
|
|
636
|
+
},
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
const bridgePathway = pathway([Providers.PULSECHAIN, Chains.PLS, Chains.ETH], true)!;
|
|
640
|
+
|
|
641
|
+
await expect(
|
|
642
|
+
loadBridgeFees({
|
|
643
|
+
pathway: bridgePathway,
|
|
644
|
+
fromChainClient: mockFromClient,
|
|
645
|
+
toChainClient: mockToClient,
|
|
646
|
+
}),
|
|
647
|
+
).rejects.toThrow('unable to read feeManager');
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
it('should handle feeManager address without zero padding (line 414 coverage)', async () => {
|
|
651
|
+
const { getContract } = await import('viem');
|
|
652
|
+
|
|
653
|
+
let callCount = 0;
|
|
654
|
+
const mockAggregate3 = vi.fn().mockImplementation(() => {
|
|
655
|
+
callCount++;
|
|
656
|
+
if (callCount === 1) {
|
|
657
|
+
// Return feeManager address WITHOUT zero padding (triggers line 414)
|
|
658
|
+
return Promise.resolve([
|
|
659
|
+
{
|
|
660
|
+
success: true,
|
|
661
|
+
returnData: '0x1234567890123456789012345678901234567890ABCDEFABCDEFABCDEF' as Hex,
|
|
662
|
+
},
|
|
663
|
+
]);
|
|
664
|
+
} else if (callCount === 2) {
|
|
665
|
+
return Promise.resolve([
|
|
666
|
+
{
|
|
667
|
+
success: true,
|
|
668
|
+
returnData:
|
|
669
|
+
'0x0000000000000000000000000000000000000000000000000000000000000001' as Hex,
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
success: true,
|
|
673
|
+
returnData:
|
|
674
|
+
'0x0000000000000000000000000000000000000000000000000000000000000002' as Hex,
|
|
675
|
+
},
|
|
676
|
+
]);
|
|
677
|
+
} else {
|
|
678
|
+
return Promise.resolve([
|
|
679
|
+
{
|
|
680
|
+
success: true,
|
|
681
|
+
returnData:
|
|
682
|
+
'0x0000000000000000000000000000000000000000000000000de0b6b3a7640000' as Hex,
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
success: true,
|
|
686
|
+
returnData:
|
|
687
|
+
'0x0000000000000000000000000000000000000000000000001bc16d674ec80000' as Hex,
|
|
688
|
+
},
|
|
689
|
+
]);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
(getContract as any).mockReturnValue({
|
|
694
|
+
read: {
|
|
695
|
+
aggregate3: mockAggregate3,
|
|
696
|
+
},
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
const bridgePathway = {
|
|
700
|
+
...pathway([Providers.PULSECHAIN, Chains.PLS, Chains.ETH], true)!,
|
|
701
|
+
feeManager: 'from' as const,
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
const result = await loadBridgeFees({
|
|
705
|
+
pathway: bridgePathway,
|
|
706
|
+
fromChainClient: mockFromClient,
|
|
707
|
+
toChainClient: mockToClient,
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
expect(result).toBeDefined();
|
|
711
|
+
expect(result.feeManager).toBeDefined();
|
|
712
|
+
// Verify the address was extracted from the last 40 characters (slice(-40))
|
|
713
|
+
expect(result.feeManager.toLowerCase()).toBe('0x9012345678901234567890abcdefabcdefabcdef');
|
|
714
|
+
});
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
describe('minBridgeAmountIn', () => {
|
|
718
|
+
let mockFromClient: any;
|
|
719
|
+
let mockToClient: any;
|
|
720
|
+
let mockAssetIn: any;
|
|
721
|
+
|
|
722
|
+
beforeEach(() => {
|
|
723
|
+
mockFromClient = {
|
|
724
|
+
chain: { id: 1 },
|
|
725
|
+
readContract: vi.fn(),
|
|
726
|
+
};
|
|
727
|
+
mockToClient = {
|
|
728
|
+
chain: { id: 369 },
|
|
729
|
+
readContract: vi.fn(),
|
|
730
|
+
};
|
|
731
|
+
mockAssetIn = {
|
|
732
|
+
address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as Hex,
|
|
733
|
+
symbol: 'USDC',
|
|
734
|
+
decimals: 6,
|
|
735
|
+
chainId: 1,
|
|
736
|
+
};
|
|
737
|
+
vi.clearAllMocks();
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
it('should fetch min amount from "from" side', async () => {
|
|
741
|
+
const bridgePathway = {
|
|
742
|
+
...pathway([Providers.PULSECHAIN, Chains.PLS, Chains.ETH], true)!,
|
|
743
|
+
feeManager: 'from' as const,
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
(mockFromClient.readContract as any).mockResolvedValue(1000000000000000n);
|
|
747
|
+
|
|
748
|
+
const result = await minBridgeAmountIn({
|
|
749
|
+
assetIn: mockAssetIn,
|
|
750
|
+
pathway: bridgePathway,
|
|
751
|
+
fromPublicClient: mockFromClient,
|
|
752
|
+
toPublicClient: mockToClient,
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
expect(result).toBe(1000000000000000n);
|
|
756
|
+
expect(mockFromClient.readContract).toHaveBeenCalled();
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
it('should fetch min amount from "to" side', async () => {
|
|
760
|
+
const bridgePathway = {
|
|
761
|
+
...pathway([Providers.PULSECHAIN, Chains.ETH, Chains.PLS], true)!,
|
|
762
|
+
feeManager: 'to' as const,
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
(mockToClient.readContract as any).mockResolvedValue(2000000000000000n);
|
|
766
|
+
|
|
767
|
+
const result = await minBridgeAmountIn({
|
|
768
|
+
assetIn: mockAssetIn,
|
|
769
|
+
pathway: bridgePathway,
|
|
770
|
+
fromPublicClient: mockFromClient,
|
|
771
|
+
toPublicClient: mockToClient,
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
expect(result).toBe(2000000000000000n);
|
|
775
|
+
expect(mockToClient.readContract).toHaveBeenCalled();
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
describe('fetchPriceCorrective', () => {
|
|
780
|
+
let mockFromClient: any;
|
|
781
|
+
let mockToClient: any;
|
|
782
|
+
let mockAssetOut: any;
|
|
783
|
+
let mockAssetLink: any;
|
|
784
|
+
|
|
785
|
+
beforeEach(() => {
|
|
786
|
+
mockFromClient = { chain: { id: 1 } };
|
|
787
|
+
mockToClient = { chain: { id: 369 } };
|
|
788
|
+
mockAssetOut = {
|
|
789
|
+
address: '0xAssetOut123456789012345678901234567890' as Hex,
|
|
790
|
+
symbol: 'OUT',
|
|
791
|
+
decimals: 18,
|
|
792
|
+
name: 'Asset Out',
|
|
793
|
+
chainId: 1,
|
|
794
|
+
logoURI: null,
|
|
795
|
+
};
|
|
796
|
+
mockAssetLink = {
|
|
797
|
+
assetInAddress: '0xAssetIn1234567890123456789012345678901' as Hex,
|
|
798
|
+
assetOutAddress: '0xAssetOut123456789012345678901234567890' as Hex,
|
|
799
|
+
originationChainId: 1,
|
|
800
|
+
};
|
|
801
|
+
vi.clearAllMocks();
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
it('should return helper object with three functions', () => {
|
|
805
|
+
const result = fetchPriceCorrective({
|
|
806
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
807
|
+
bridgeKeyPartner: [Providers.PULSECHAIN, Chains.ETH, Chains.PLS],
|
|
808
|
+
measurementToken: '0x1234567890123456789012345678901234567890' as Hex,
|
|
809
|
+
assetOut: mockAssetOut,
|
|
810
|
+
fromChainClient: mockFromClient,
|
|
811
|
+
toChainClient: mockToClient,
|
|
812
|
+
assetLink: mockAssetLink,
|
|
813
|
+
amountIn: 1000000000000000000n,
|
|
814
|
+
isProd: true,
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
expect(result).toBeDefined();
|
|
818
|
+
expect(result.getPaymentToken).toBeInstanceOf(Function);
|
|
819
|
+
expect(result.getSwapResults).toBeInstanceOf(Function);
|
|
820
|
+
expect(result.reduceResults).toBeInstanceOf(Function);
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
it('should call tokenBridgeInfo in getPaymentToken', async () => {
|
|
824
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
825
|
+
(multicallRead as any).mockReset();
|
|
826
|
+
(multicallRead as any)
|
|
827
|
+
.mockResolvedValueOnce(['0x1234567890123456789012345678901234567890' as Hex, zeroAddress])
|
|
828
|
+
.mockResolvedValueOnce([zeroAddress, zeroAddress]);
|
|
829
|
+
(links as any).cache = new Map();
|
|
830
|
+
|
|
831
|
+
const helpers = fetchPriceCorrective({
|
|
832
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
833
|
+
bridgeKeyPartner: [Providers.PULSECHAIN, Chains.ETH, Chains.PLS],
|
|
834
|
+
measurementToken: '0x1234567890123456789012345678901234567890' as Hex,
|
|
835
|
+
assetOut: mockAssetOut,
|
|
836
|
+
fromChainClient: mockFromClient,
|
|
837
|
+
toChainClient: mockToClient,
|
|
838
|
+
assetLink: mockAssetLink,
|
|
839
|
+
amountIn: 1000000000000000000n,
|
|
840
|
+
isProd: true,
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
const paymentToken = await helpers.getPaymentToken();
|
|
844
|
+
|
|
845
|
+
expect(paymentToken).toBeDefined();
|
|
846
|
+
expect(multicallRead).toHaveBeenCalled();
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
it('should call readAmountOut twice in getSwapResults', async () => {
|
|
850
|
+
const { multicallRead } = await import('@gibs/common/multicall');
|
|
851
|
+
(multicallRead as any).mockReset();
|
|
852
|
+
(multicallRead as any).mockResolvedValue([[1000000000000000000n, 950000000000000000n]]);
|
|
853
|
+
|
|
854
|
+
const helpers = fetchPriceCorrective({
|
|
855
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
856
|
+
bridgeKeyPartner: [Providers.PULSECHAIN, Chains.ETH, Chains.PLS],
|
|
857
|
+
measurementToken: '0x1234567890123456789012345678901234567890' as Hex,
|
|
858
|
+
assetOut: mockAssetOut,
|
|
859
|
+
fromChainClient: mockFromClient,
|
|
860
|
+
toChainClient: mockToClient,
|
|
861
|
+
assetLink: mockAssetLink,
|
|
862
|
+
amountIn: 1000000000000000000n,
|
|
863
|
+
isProd: true,
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
const mockPaymentTokenResult = {
|
|
867
|
+
assetInAddress: '0xAssetIn1234567890123456789012345678901' as Hex,
|
|
868
|
+
assetOutAddress: '0xPaymentOut12345678901234567890123456789' as Hex,
|
|
869
|
+
originationChainId: 1,
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
const results = await helpers.getSwapResults({
|
|
873
|
+
paymentTokenResult: mockPaymentTokenResult,
|
|
874
|
+
chain: Chains.PLS,
|
|
875
|
+
client: mockFromClient,
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
expect(results).toBeDefined();
|
|
879
|
+
expect(Array.isArray(results)).toBe(true);
|
|
880
|
+
expect(results).toHaveLength(2);
|
|
881
|
+
expect(multicallRead).toHaveBeenCalledTimes(2);
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
it('should calculate maximum output in reduceResults', () => {
|
|
885
|
+
const helpers = fetchPriceCorrective({
|
|
886
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
887
|
+
bridgeKeyPartner: [Providers.PULSECHAIN, Chains.ETH, Chains.PLS],
|
|
888
|
+
measurementToken: '0x1234567890123456789012345678901234567890' as Hex,
|
|
889
|
+
assetOut: mockAssetOut,
|
|
890
|
+
fromChainClient: mockFromClient,
|
|
891
|
+
toChainClient: mockToClient,
|
|
892
|
+
assetLink: mockAssetLink,
|
|
893
|
+
amountIn: 1000000000000000000n,
|
|
894
|
+
isProd: true,
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
const mockResults: [[bigint[]], [bigint[]]] = [
|
|
898
|
+
[[1000000000000000000n, 950000000000000000n]], // outputs
|
|
899
|
+
[[1000000000000000000n, 980000000000000000n]], // inputs
|
|
900
|
+
];
|
|
901
|
+
|
|
902
|
+
const result = helpers.reduceResults({
|
|
903
|
+
results: mockResults,
|
|
904
|
+
oneToken: 1000000000000000000n,
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
expect(result).toBeDefined();
|
|
908
|
+
expect(typeof result).toBe('bigint');
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
it('should handle failed router results in reduceResults', () => {
|
|
912
|
+
const helpers = fetchPriceCorrective({
|
|
913
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
914
|
+
bridgeKeyPartner: [Providers.PULSECHAIN, Chains.ETH, Chains.PLS],
|
|
915
|
+
measurementToken: '0x1234567890123456789012345678901234567890' as Hex,
|
|
916
|
+
assetOut: mockAssetOut,
|
|
917
|
+
fromChainClient: mockFromClient,
|
|
918
|
+
toChainClient: mockToClient,
|
|
919
|
+
assetLink: mockAssetLink,
|
|
920
|
+
amountIn: 1000000000000000000n,
|
|
921
|
+
isProd: true,
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
// Test with failed router results (Hex strings instead of bigint arrays)
|
|
925
|
+
const mockResults: [[Hex | bigint[]], [bigint[]]] = [
|
|
926
|
+
['0xERROR' as Hex], // Failed router call returns Hex
|
|
927
|
+
[[1000000000000000000n, 980000000000000000n]], // inputs
|
|
928
|
+
];
|
|
929
|
+
|
|
930
|
+
const result = helpers.reduceResults({
|
|
931
|
+
results: mockResults as any,
|
|
932
|
+
oneToken: 1000000000000000000n,
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
expect(result).toBeDefined();
|
|
936
|
+
// Should fall back to input token calculation
|
|
937
|
+
expect(result).toBeGreaterThan(0n);
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
it('should handle empty router results in reduceResults', () => {
|
|
941
|
+
const helpers = fetchPriceCorrective({
|
|
942
|
+
bridgeKey: [Providers.PULSECHAIN, Chains.PLS, Chains.ETH],
|
|
943
|
+
bridgeKeyPartner: [Providers.PULSECHAIN, Chains.ETH, Chains.PLS],
|
|
944
|
+
measurementToken: '0x1234567890123456789012345678901234567890' as Hex,
|
|
945
|
+
assetOut: mockAssetOut,
|
|
946
|
+
fromChainClient: mockFromClient,
|
|
947
|
+
toChainClient: mockToClient,
|
|
948
|
+
assetLink: mockAssetLink,
|
|
949
|
+
amountIn: 1000000000000000000n,
|
|
950
|
+
isProd: true,
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
// Test with empty results
|
|
954
|
+
const mockResults: [[bigint[]], [bigint[]]] = [
|
|
955
|
+
[[]], // Empty output array
|
|
956
|
+
[[1000000000000000000n, 980000000000000000n]], // inputs
|
|
957
|
+
];
|
|
958
|
+
|
|
959
|
+
const result = helpers.reduceResults({
|
|
960
|
+
results: mockResults,
|
|
961
|
+
oneToken: 1000000000000000000n,
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
expect(result).toBeDefined();
|
|
965
|
+
expect(result).toBeGreaterThan(0n);
|
|
966
|
+
});
|
|
967
|
+
});
|
|
968
|
+
});
|