@rango-dev/widget-embedded 0.30.1-next.3 → 0.30.1-next.5
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/components/Quote/Quote.styles.d.ts +1 -1
- package/dist/components/RefreshModal/RefreshModal.styles.d.ts +1 -1
- package/dist/containers/Wallets/Wallets.d.ts.map +1 -1
- package/dist/hooks/usePrepareBlockchainList/usePrepareBlockchainList.helpers.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +4 -4
- package/dist/services/cacheService.d.ts +21 -0
- package/dist/services/cacheService.d.ts.map +1 -0
- package/dist/store/notification.d.ts.map +1 -1
- package/dist/store/slices/config.d.ts +2 -1
- package/dist/store/slices/config.d.ts.map +1 -1
- package/dist/store/slices/data.d.ts +2 -1
- package/dist/store/slices/data.d.ts.map +1 -1
- package/dist/store/utils/data.d.ts +20 -0
- package/dist/store/utils/data.d.ts.map +1 -0
- package/dist/store/utils/data.test.d.ts +2 -0
- package/dist/store/utils/data.test.d.ts.map +1 -0
- package/dist/store/utils/index.d.ts +2 -0
- package/dist/store/utils/index.d.ts.map +1 -0
- package/dist/test-utils/fixtures.d.ts +1 -0
- package/dist/test-utils/fixtures.d.ts.map +1 -1
- package/dist/types/notification.d.ts +1 -0
- package/dist/types/notification.d.ts.map +1 -1
- package/dist/types/wallets.d.ts +1 -1
- package/dist/types/wallets.d.ts.map +1 -1
- package/dist/utils/settings.d.ts +1 -1
- package/dist/widget-embedded.build.json +1 -1
- package/package.json +2 -2
- package/src/containers/Wallets/Wallets.tsx +7 -2
- package/src/services/cacheService.ts +35 -0
- package/src/store/notification.ts +13 -1
- package/src/store/slices/config.ts +39 -1
- package/src/store/slices/data.test.ts +84 -0
- package/src/store/slices/data.ts +44 -24
- package/src/store/utils/data.test.ts +175 -0
- package/src/store/utils/data.ts +117 -0
- package/src/store/utils/index.ts +1 -0
- package/src/test-utils/fixtures.ts +14 -7
- package/src/types/notification.ts +1 -0
- package/src/types/wallets.ts +1 -1
package/package.json
CHANGED
|
@@ -31,7 +31,12 @@ export const WidgetContext = createContext<WidgetContextInterface>({
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
function Main(props: PropsWithChildren<PropTypes>) {
|
|
34
|
-
const {
|
|
34
|
+
const {
|
|
35
|
+
updateConfig,
|
|
36
|
+
updateSettings,
|
|
37
|
+
fetch: fetchMeta,
|
|
38
|
+
fetchStatus,
|
|
39
|
+
} = useAppStore();
|
|
35
40
|
const blockchains = useAppStore().blockchains();
|
|
36
41
|
const { findToken } = useAppStore();
|
|
37
42
|
const config = useAppStore().config;
|
|
@@ -61,7 +66,7 @@ function Main(props: PropsWithChildren<PropTypes>) {
|
|
|
61
66
|
dappConfig: props.config,
|
|
62
67
|
};
|
|
63
68
|
}
|
|
64
|
-
}, [props.config]);
|
|
69
|
+
}, [props.config, fetchStatus]);
|
|
65
70
|
|
|
66
71
|
const evmBasedChainNames = blockchains
|
|
67
72
|
.filter(isEvmBlockchain)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Token } from 'rango-sdk';
|
|
2
|
+
|
|
3
|
+
interface CacheServiceInterface<V> {
|
|
4
|
+
get<K extends keyof V>(key: K): V[K] | undefined;
|
|
5
|
+
set<K extends keyof V>(key: K, value: V[K]): void;
|
|
6
|
+
remove<K extends keyof V>(key: K): void;
|
|
7
|
+
clear(): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
class CacheService<T> implements CacheServiceInterface<T> {
|
|
11
|
+
#cache: Map<string, T[keyof T]> = new Map();
|
|
12
|
+
|
|
13
|
+
get<K extends keyof T>(key: K): T[K] | undefined {
|
|
14
|
+
return this.#cache.get(key as string) as T[K];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
set<K extends keyof T>(key: K, value: T[K]): void {
|
|
18
|
+
this.#cache.set(key as string, value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
remove<K extends keyof T>(key: K): void {
|
|
22
|
+
this.#cache.delete(key as string);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
clear(): void {
|
|
26
|
+
this.#cache.clear();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type CachedEntries = {
|
|
31
|
+
supportedSourceTokens: Token[];
|
|
32
|
+
supportedDestinationTokens: Token[];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const cacheService = new CacheService<CachedEntries>();
|
|
@@ -36,6 +36,7 @@ export const useNotificationStore = createSelectors(
|
|
|
36
36
|
creationTime: Date.now(),
|
|
37
37
|
requestId: route.requestId,
|
|
38
38
|
route: {
|
|
39
|
+
creationTime: parseInt(route.creationTime),
|
|
39
40
|
from: {
|
|
40
41
|
blockchain: fromStep.fromBlockchain,
|
|
41
42
|
address: fromStep.fromSymbolAddress,
|
|
@@ -67,7 +68,18 @@ export const useNotificationStore = createSelectors(
|
|
|
67
68
|
getNotifications: () => {
|
|
68
69
|
const { isSynced, notifications } = get();
|
|
69
70
|
return isSynced
|
|
70
|
-
? notifications.sort((a, b) =>
|
|
71
|
+
? notifications.sort((a, b) => {
|
|
72
|
+
if (a.route.creationTime && !b.route.creationTime) {
|
|
73
|
+
return -1;
|
|
74
|
+
}
|
|
75
|
+
if (!a.route.creationTime && b.route.creationTime) {
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
if (!a.route.creationTime && !b.route.creationTime) {
|
|
79
|
+
return b.creationTime - a.creationTime;
|
|
80
|
+
}
|
|
81
|
+
return b.route.creationTime - a.route.creationTime;
|
|
82
|
+
})
|
|
71
83
|
: [];
|
|
72
84
|
},
|
|
73
85
|
syncNotifications: (swaps) => {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import type { DataSlice } from './data';
|
|
1
2
|
import type { SettingsSlice } from './settings';
|
|
2
3
|
import type { WidgetConfig } from '../../types';
|
|
3
4
|
import type { StateCreatorWithInitialData } from '../app';
|
|
4
5
|
|
|
6
|
+
import { cacheService } from '../../services/cacheService';
|
|
7
|
+
import { matchTokensFromConfigWithMeta } from '../utils';
|
|
8
|
+
|
|
5
9
|
export const DEFAULT_CONFIG: WidgetConfig = {
|
|
6
10
|
apiKey: '',
|
|
7
11
|
title: undefined,
|
|
@@ -54,7 +58,7 @@ export interface ConfigSlice {
|
|
|
54
58
|
|
|
55
59
|
export const createConfigSlice: StateCreatorWithInitialData<
|
|
56
60
|
WidgetConfig,
|
|
57
|
-
ConfigSlice & SettingsSlice,
|
|
61
|
+
ConfigSlice & SettingsSlice & DataSlice,
|
|
58
62
|
ConfigSlice
|
|
59
63
|
> = (initialData, set, get) => {
|
|
60
64
|
return {
|
|
@@ -87,6 +91,40 @@ export const createConfigSlice: StateCreatorWithInitialData<
|
|
|
87
91
|
// Actions
|
|
88
92
|
updateConfig: (nextConfig: WidgetConfig) => {
|
|
89
93
|
const currentConfig = get().config;
|
|
94
|
+
const {
|
|
95
|
+
_tokensMapByTokenHash: tokensMapByTokenHash,
|
|
96
|
+
_tokensMapByBlockchainName: tokensMapByBlockchainName,
|
|
97
|
+
} = get();
|
|
98
|
+
|
|
99
|
+
const supportedSourceTokens = matchTokensFromConfigWithMeta({
|
|
100
|
+
type: 'source',
|
|
101
|
+
config: {
|
|
102
|
+
blockchains: nextConfig.from?.blockchains,
|
|
103
|
+
tokens: nextConfig.from?.tokens,
|
|
104
|
+
},
|
|
105
|
+
meta: {
|
|
106
|
+
tokensMapByBlockchainName,
|
|
107
|
+
tokensMapByTokenHash,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const supportedDestinationTokens = matchTokensFromConfigWithMeta({
|
|
112
|
+
type: 'destination',
|
|
113
|
+
config: {
|
|
114
|
+
blockchains: nextConfig.to?.blockchains,
|
|
115
|
+
tokens: nextConfig.to?.tokens,
|
|
116
|
+
},
|
|
117
|
+
meta: {
|
|
118
|
+
tokensMapByBlockchainName,
|
|
119
|
+
tokensMapByTokenHash,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
cacheService.set('supportedSourceTokens', supportedSourceTokens);
|
|
124
|
+
cacheService.set(
|
|
125
|
+
'supportedDestinationTokens',
|
|
126
|
+
supportedDestinationTokens
|
|
127
|
+
);
|
|
90
128
|
|
|
91
129
|
set({
|
|
92
130
|
config: {
|
|
@@ -3,6 +3,7 @@ import type { EvmBlockchainMeta, Token } from 'rango-sdk';
|
|
|
3
3
|
|
|
4
4
|
import { assert, beforeEach, describe, expect, test } from 'vitest';
|
|
5
5
|
|
|
6
|
+
import { cacheService } from '../../services/cacheService';
|
|
6
7
|
import {
|
|
7
8
|
createEvmBlockchain,
|
|
8
9
|
createInitialAppStore,
|
|
@@ -17,6 +18,7 @@ let customTokens: [Token, Token, Token];
|
|
|
17
18
|
let rangoBlockchain: EvmBlockchainMeta;
|
|
18
19
|
|
|
19
20
|
beforeEach(() => {
|
|
21
|
+
cacheService.clear();
|
|
20
22
|
rangoBlockchain = createEvmBlockchain();
|
|
21
23
|
|
|
22
24
|
customTokens = [
|
|
@@ -52,6 +54,10 @@ beforeEach(() => {
|
|
|
52
54
|
customTokens.forEach((token) => {
|
|
53
55
|
const tokenHash = createTokenHash(token);
|
|
54
56
|
initData._tokensMapByTokenHash.set(tokenHash, token);
|
|
57
|
+
if (!initData._tokensMapByBlockchainName[token.blockchain]) {
|
|
58
|
+
initData._tokensMapByBlockchainName[token.blockchain] = [];
|
|
59
|
+
}
|
|
60
|
+
initData._tokensMapByBlockchainName[token.blockchain].push(tokenHash);
|
|
55
61
|
});
|
|
56
62
|
|
|
57
63
|
const appStore = createAppStore();
|
|
@@ -351,3 +357,81 @@ describe('search in tokens', () => {
|
|
|
351
357
|
expect(secondResult).toBe('RNG');
|
|
352
358
|
});
|
|
353
359
|
});
|
|
360
|
+
|
|
361
|
+
describe('supported tokens from config', () => {
|
|
362
|
+
test('Should ensure tokens include only tokens from the config', () => {
|
|
363
|
+
const rangoToken = customTokens[0];
|
|
364
|
+
const djangoToken = customTokens[1];
|
|
365
|
+
|
|
366
|
+
const configTokens = [rangoToken, djangoToken];
|
|
367
|
+
|
|
368
|
+
appStoreState = updateAppStoreConfig(appStoreState, {
|
|
369
|
+
from: {
|
|
370
|
+
tokens: configTokens,
|
|
371
|
+
},
|
|
372
|
+
to: { tokens: configTokens },
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
let sourceTokens = appStoreState.tokens({
|
|
376
|
+
type: 'source',
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
let destinationTokens = appStoreState.tokens({
|
|
380
|
+
type: 'destination',
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
expect(configTokens).toMatchObject(sourceTokens);
|
|
384
|
+
expect(configTokens).toMatchObject(destinationTokens);
|
|
385
|
+
|
|
386
|
+
appStoreState = updateAppStoreConfig(appStoreState, {
|
|
387
|
+
from: {
|
|
388
|
+
blockchains: [rangoBlockchain.name],
|
|
389
|
+
tokens: {
|
|
390
|
+
[rangoBlockchain.name]: {
|
|
391
|
+
tokens: configTokens,
|
|
392
|
+
isExcluded: false,
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
to: {
|
|
397
|
+
blockchains: [rangoBlockchain.name],
|
|
398
|
+
tokens: {
|
|
399
|
+
[rangoBlockchain.name]: {
|
|
400
|
+
tokens: configTokens,
|
|
401
|
+
isExcluded: false,
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
sourceTokens = appStoreState.tokens({
|
|
408
|
+
type: 'source',
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
destinationTokens = appStoreState.tokens({
|
|
412
|
+
type: 'destination',
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
expect(sourceTokens).toMatchObject(sourceTokens);
|
|
416
|
+
expect(configTokens).toMatchObject(destinationTokens);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
test('Check tokens calculation is caching', () => {
|
|
420
|
+
const rangoToken = customTokens[0];
|
|
421
|
+
const djangoToken = customTokens[1];
|
|
422
|
+
|
|
423
|
+
appStoreState = updateAppStoreConfig(appStoreState, {
|
|
424
|
+
from: {
|
|
425
|
+
tokens: [rangoToken, djangoToken],
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
expect(cacheService.get('supportedSourceTokens')?.length ?? 0).toBe(0);
|
|
430
|
+
|
|
431
|
+
appStoreState.tokens({
|
|
432
|
+
type: 'source',
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
expect(cacheService.get('supportedSourceTokens')?.length ?? 0).toBe(2);
|
|
436
|
+
});
|
|
437
|
+
});
|
package/src/store/slices/data.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
// We keep all the received data from server in this slice
|
|
2
2
|
|
|
3
3
|
import type { ConfigSlice } from './config';
|
|
4
|
-
import type {
|
|
4
|
+
import type { CachedEntries } from '../../services/cacheService';
|
|
5
|
+
import type { Balance, Blockchain, TokenHash } from '../../types';
|
|
5
6
|
import type { Asset, BlockchainMeta, SwapperMeta, Token } from 'rango-sdk';
|
|
6
7
|
import type { StateCreator } from 'zustand';
|
|
7
8
|
|
|
9
|
+
import { cacheService } from '../../services/cacheService';
|
|
8
10
|
import { httpService as sdk } from '../../services/httpService';
|
|
9
11
|
import { compareWithSearchFor, containsText } from '../../utils/common';
|
|
10
|
-
import { isTokenExcludedInConfig } from '../../utils/configs';
|
|
11
12
|
import { createTokenHash, isTokenNative } from '../../utils/meta';
|
|
12
13
|
import { sortLiquiditySourcesByGroupTitle } from '../../utils/settings';
|
|
13
14
|
import { areTokensEqual, compareTokenBalance } from '../../utils/wallets';
|
|
15
|
+
import { matchTokensFromConfigWithMeta } from '../utils';
|
|
14
16
|
|
|
15
17
|
type BlockchainOptions = {
|
|
16
18
|
type?: 'source' | 'destination';
|
|
@@ -30,6 +32,7 @@ export type FetchStatus = 'loading' | 'success' | 'failed';
|
|
|
30
32
|
export interface DataSlice {
|
|
31
33
|
_blockchainsMapByName: Map<string, BlockchainMeta>;
|
|
32
34
|
_tokensMapByTokenHash: Map<TokenHash, Token>;
|
|
35
|
+
_tokensMapByBlockchainName: Record<Blockchain, TokenHash[]>;
|
|
33
36
|
_popularTokens: Token[];
|
|
34
37
|
_swappers: SwapperMeta[];
|
|
35
38
|
fetchStatus: FetchStatus;
|
|
@@ -48,8 +51,9 @@ export const createDataSlice: StateCreator<
|
|
|
48
51
|
DataSlice
|
|
49
52
|
> = (set, get) => ({
|
|
50
53
|
// State
|
|
51
|
-
_blockchainsMapByName: new Map
|
|
52
|
-
_tokensMapByTokenHash: new Map
|
|
54
|
+
_blockchainsMapByName: new Map(),
|
|
55
|
+
_tokensMapByTokenHash: new Map(),
|
|
56
|
+
_tokensMapByBlockchainName: {},
|
|
53
57
|
_popularTokens: [],
|
|
54
58
|
_swappers: [],
|
|
55
59
|
fetchStatus: 'loading',
|
|
@@ -84,31 +88,41 @@ export const createDataSlice: StateCreator<
|
|
|
84
88
|
return list;
|
|
85
89
|
},
|
|
86
90
|
tokens: (options) => {
|
|
87
|
-
const
|
|
88
|
-
const tokensFromState = Array.from(
|
|
91
|
+
const { _tokensMapByTokenHash, _tokensMapByBlockchainName, config } = get();
|
|
92
|
+
const tokensFromState = Array.from(_tokensMapByTokenHash.values());
|
|
89
93
|
const blockchainsMapByName = get()._blockchainsMapByName;
|
|
90
|
-
|
|
91
|
-
if (!options || !options?.type) {
|
|
94
|
+
if (!options || !options.type) {
|
|
92
95
|
return tokensFromState;
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
const configType = options.type === 'source' ? 'from' : 'to';
|
|
99
|
+
const cacheKey: keyof CachedEntries =
|
|
100
|
+
options.type === 'source'
|
|
101
|
+
? 'supportedSourceTokens'
|
|
102
|
+
: 'supportedDestinationTokens';
|
|
103
|
+
|
|
104
|
+
let supportedTokens = cacheService.get(cacheKey);
|
|
105
|
+
if (!supportedTokens) {
|
|
106
|
+
supportedTokens = matchTokensFromConfigWithMeta({
|
|
107
|
+
type: options.type,
|
|
108
|
+
config: {
|
|
109
|
+
blockchains: config[configType]?.blockchains,
|
|
110
|
+
tokens: config[configType]?.tokens,
|
|
111
|
+
},
|
|
112
|
+
meta: {
|
|
113
|
+
tokensMapByTokenHash: _tokensMapByTokenHash,
|
|
114
|
+
tokensMapByBlockchainName: _tokensMapByBlockchainName,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
cacheService.set(cacheKey, supportedTokens);
|
|
118
|
+
}
|
|
119
|
+
|
|
99
120
|
const blockchains = get().blockchains({
|
|
100
121
|
type: options.type,
|
|
101
122
|
});
|
|
102
123
|
|
|
103
|
-
const list =
|
|
124
|
+
const list = supportedTokens
|
|
104
125
|
.filter((token) => {
|
|
105
|
-
if (
|
|
106
|
-
supportedTokensConfig &&
|
|
107
|
-
isTokenExcludedInConfig(token, supportedTokensConfig)
|
|
108
|
-
) {
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
126
|
// If a specific blockchain has passed, we only keep that blockchain's tokens.
|
|
113
127
|
if (!!options.blockchain && token.blockchain !== options.blockchain) {
|
|
114
128
|
return false;
|
|
@@ -261,17 +275,18 @@ export const createDataSlice: StateCreator<
|
|
|
261
275
|
const response = await sdk().getAllMetadata({
|
|
262
276
|
enableCentralizedSwappers,
|
|
263
277
|
});
|
|
264
|
-
|
|
265
278
|
set({ fetchStatus: 'success' });
|
|
266
279
|
const blockchainsMapByName: Map<string, BlockchainMeta> = new Map<
|
|
267
280
|
string,
|
|
268
281
|
BlockchainMeta
|
|
269
282
|
>();
|
|
270
283
|
|
|
271
|
-
const
|
|
284
|
+
const tokensMapByTokenHash: Map<TokenHash, Token> = new Map<
|
|
272
285
|
TokenHash,
|
|
273
286
|
Token
|
|
274
287
|
>();
|
|
288
|
+
const tokensMapByBlockchainName: DataSlice['_tokensMapByBlockchainName'] =
|
|
289
|
+
{};
|
|
275
290
|
const tokens: Token[] = [];
|
|
276
291
|
const popularTokens: Token[] = response.popularTokens;
|
|
277
292
|
const swappers: SwapperMeta[] = response.swappers;
|
|
@@ -299,12 +314,17 @@ export const createDataSlice: StateCreator<
|
|
|
299
314
|
|
|
300
315
|
tokens.forEach((token) => {
|
|
301
316
|
const tokenHash = createTokenHash(token);
|
|
302
|
-
|
|
317
|
+
if (!tokensMapByBlockchainName[token.blockchain]) {
|
|
318
|
+
tokensMapByBlockchainName[token.blockchain] = [];
|
|
319
|
+
}
|
|
320
|
+
tokensMapByTokenHash.set(tokenHash, token);
|
|
321
|
+
tokensMapByBlockchainName[token.blockchain].push(tokenHash);
|
|
303
322
|
});
|
|
304
323
|
|
|
305
324
|
set({
|
|
306
325
|
_blockchainsMapByName: blockchainsMapByName,
|
|
307
|
-
_tokensMapByTokenHash:
|
|
326
|
+
_tokensMapByTokenHash: tokensMapByTokenHash,
|
|
327
|
+
_tokensMapByBlockchainName: tokensMapByBlockchainName,
|
|
308
328
|
_popularTokens: popularTokens,
|
|
309
329
|
_swappers: swappers,
|
|
310
330
|
});
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { Token } from 'rango-sdk';
|
|
2
|
+
|
|
3
|
+
import { describe, expect, test } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { createToken } from '../../test-utils/fixtures';
|
|
6
|
+
import { createTokenHash } from '../../utils/meta';
|
|
7
|
+
|
|
8
|
+
import { matchTokensFromConfigWithMeta } from './data'; // Adjust path as necessary
|
|
9
|
+
|
|
10
|
+
type MatchTokensFromConfigWithMetaParam = Parameters<
|
|
11
|
+
typeof matchTokensFromConfigWithMeta
|
|
12
|
+
>[0];
|
|
13
|
+
|
|
14
|
+
const BLOCKCHAIN_A = 'blockchainA';
|
|
15
|
+
const BLOCKCHAIN_B = 'blockchainB';
|
|
16
|
+
const BLOCKCHAIN_C = 'blockchainC';
|
|
17
|
+
|
|
18
|
+
const tokens: Token[] = [
|
|
19
|
+
{ ...createToken(), blockchain: BLOCKCHAIN_A },
|
|
20
|
+
{ ...createToken(), blockchain: BLOCKCHAIN_A },
|
|
21
|
+
{ ...createToken(), blockchain: BLOCKCHAIN_B },
|
|
22
|
+
{ ...createToken(), blockchain: BLOCKCHAIN_C },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
function createMetaForMockData(
|
|
26
|
+
tokens: Token[]
|
|
27
|
+
): MatchTokensFromConfigWithMetaParam['meta'] {
|
|
28
|
+
const meta: MatchTokensFromConfigWithMetaParam['meta'] = {
|
|
29
|
+
tokensMapByTokenHash: new Map(),
|
|
30
|
+
tokensMapByBlockchainName: {},
|
|
31
|
+
};
|
|
32
|
+
tokens.forEach((token) => {
|
|
33
|
+
const tokenHash = createTokenHash(token);
|
|
34
|
+
meta.tokensMapByTokenHash.set(tokenHash, token);
|
|
35
|
+
if (!meta.tokensMapByBlockchainName[token.blockchain]) {
|
|
36
|
+
meta.tokensMapByBlockchainName[token.blockchain] = [];
|
|
37
|
+
}
|
|
38
|
+
meta.tokensMapByBlockchainName[token.blockchain].push(tokenHash);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return meta;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe('matchTokensFromConfigWithMeta', () => {
|
|
45
|
+
test('should include tokens from config.tokens array that exist in meta', () => {
|
|
46
|
+
const mockData: MatchTokensFromConfigWithMetaParam = {
|
|
47
|
+
type: 'source',
|
|
48
|
+
meta: createMetaForMockData(tokens),
|
|
49
|
+
config: {
|
|
50
|
+
blockchains: undefined,
|
|
51
|
+
tokens: [tokens[0], tokens[1]],
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const result = matchTokensFromConfigWithMeta(mockData);
|
|
56
|
+
expect(result).toEqual([tokens[0], tokens[1]]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('If config.blockchains is not defined or is empty, we should include all tokens from the meta for every blockchain that does not have tokens specified in the config, as well as tokens specified in the config that exist in the meta.', () => {
|
|
60
|
+
const mockData: MatchTokensFromConfigWithMetaParam = {
|
|
61
|
+
type: 'source',
|
|
62
|
+
meta: createMetaForMockData(tokens),
|
|
63
|
+
config: {
|
|
64
|
+
blockchains: undefined,
|
|
65
|
+
tokens: {
|
|
66
|
+
[BLOCKCHAIN_A]: { tokens: [tokens[0]], isExcluded: false },
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const runTestWithConfig = (config: {
|
|
72
|
+
blockchains: MatchTokensFromConfigWithMetaParam['config']['blockchains'];
|
|
73
|
+
}) => {
|
|
74
|
+
mockData.config.blockchains = config.blockchains;
|
|
75
|
+
const result = matchTokensFromConfigWithMeta(mockData);
|
|
76
|
+
/**
|
|
77
|
+
* In this case, the result might differ from what was expected.
|
|
78
|
+
* To pass the test, we reordered the expected result.
|
|
79
|
+
* Changing the order of tokens does not impact the overall behavior of our app,
|
|
80
|
+
* as we have a comprehensive sorting logic applied to tokens within the data slice.
|
|
81
|
+
*/
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
|
83
|
+
expect(result).toEqual([tokens[2], tokens[3], tokens[0]]);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
runTestWithConfig({ blockchains: undefined });
|
|
87
|
+
runTestWithConfig({ blockchains: [] });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('should include tokens from config.tokens object that exist in meta', () => {
|
|
91
|
+
const mockData: MatchTokensFromConfigWithMetaParam = {
|
|
92
|
+
type: 'source',
|
|
93
|
+
meta: createMetaForMockData(tokens),
|
|
94
|
+
config: {
|
|
95
|
+
blockchains: [BLOCKCHAIN_A, BLOCKCHAIN_B],
|
|
96
|
+
tokens: {
|
|
97
|
+
[BLOCKCHAIN_A]: { tokens: [tokens[0]], isExcluded: false },
|
|
98
|
+
[BLOCKCHAIN_B]: { tokens: [tokens[2]], isExcluded: false },
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const result = matchTokensFromConfigWithMeta(mockData);
|
|
104
|
+
expect(result).toEqual([tokens[0], tokens[2]]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('should not include tokens from config.tokens whose blockchain does not exist in config.blockchains', () => {
|
|
108
|
+
const mockData: MatchTokensFromConfigWithMetaParam = {
|
|
109
|
+
type: 'source',
|
|
110
|
+
meta: createMetaForMockData(tokens),
|
|
111
|
+
config: {
|
|
112
|
+
blockchains: [BLOCKCHAIN_A],
|
|
113
|
+
tokens: {
|
|
114
|
+
[BLOCKCHAIN_B]: { tokens: [tokens[2]], isExcluded: false },
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const result = matchTokensFromConfigWithMeta(mockData);
|
|
120
|
+
expect(result).toEqual([tokens[0], tokens[1]]);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('should include all tokens from a blockchain if that blockchain does not have any tokens in config.tokens', () => {
|
|
124
|
+
const mockData: MatchTokensFromConfigWithMetaParam = {
|
|
125
|
+
type: 'source',
|
|
126
|
+
meta: createMetaForMockData(tokens),
|
|
127
|
+
config: {
|
|
128
|
+
blockchains: [BLOCKCHAIN_A],
|
|
129
|
+
tokens: {},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const result = matchTokensFromConfigWithMeta(mockData);
|
|
134
|
+
expect(result).toEqual([tokens[0], tokens[1]]);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('should include all tokens from config.blockchains that exist in the meta, except tokens excluded in config.token', () => {
|
|
138
|
+
const mockData: MatchTokensFromConfigWithMetaParam = {
|
|
139
|
+
type: 'source',
|
|
140
|
+
meta: createMetaForMockData(tokens),
|
|
141
|
+
config: {
|
|
142
|
+
blockchains: [BLOCKCHAIN_A],
|
|
143
|
+
tokens: {
|
|
144
|
+
[BLOCKCHAIN_A]: { tokens: [tokens[0]], isExcluded: true },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const result = matchTokensFromConfigWithMeta(mockData);
|
|
150
|
+
expect(result).toEqual([tokens[1]]);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('should include all tokens from the meta when config parameters are empty values', () => {
|
|
154
|
+
const mockData: MatchTokensFromConfigWithMetaParam = {
|
|
155
|
+
type: 'source',
|
|
156
|
+
meta: createMetaForMockData(tokens),
|
|
157
|
+
config: {
|
|
158
|
+
blockchains: [],
|
|
159
|
+
tokens: {},
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const runTestWithConfig = (
|
|
164
|
+
config: MatchTokensFromConfigWithMetaParam['config']
|
|
165
|
+
) => {
|
|
166
|
+
mockData.config = config;
|
|
167
|
+
const result = matchTokensFromConfigWithMeta(mockData);
|
|
168
|
+
expect(result).toEqual(tokens);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
runTestWithConfig({ blockchains: [], tokens: {} });
|
|
172
|
+
runTestWithConfig({ blockchains: undefined, tokens: undefined });
|
|
173
|
+
runTestWithConfig({ blockchains: [], tokens: [] });
|
|
174
|
+
});
|
|
175
|
+
});
|