@0xsquid/react-hooks 1.0.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.
Files changed (108) hide show
  1. package/.babelrc +7 -0
  2. package/.eslintignore +1 -0
  3. package/.eslintrc.json +44 -0
  4. package/dist/index.js +6 -0
  5. package/jest.config.ts +28 -0
  6. package/package.json +124 -0
  7. package/scripts/copyAssets.js +27 -0
  8. package/scripts/removeBuildTestFolder.js +28 -0
  9. package/scripts/replacePaths.js +37 -0
  10. package/src/assets/images/icons/wallets/binance.svg +4 -0
  11. package/src/assets/images/icons/wallets/bitget.svg +43 -0
  12. package/src/assets/images/icons/wallets/bitkeep.svg +9 -0
  13. package/src/assets/images/icons/wallets/blockchaindotcom.svg +11 -0
  14. package/src/assets/images/icons/wallets/brave.svg +18 -0
  15. package/src/assets/images/icons/wallets/c98.svg +3 -0
  16. package/src/assets/images/icons/wallets/coinbase.svg +5 -0
  17. package/src/assets/images/icons/wallets/cosmostation.svg +9 -0
  18. package/src/assets/images/icons/wallets/defiConnect.svg +25 -0
  19. package/src/assets/images/icons/wallets/exodus.svg +33 -0
  20. package/src/assets/images/icons/wallets/fetchai.svg +1 -0
  21. package/src/assets/images/icons/wallets/index.ts +43 -0
  22. package/src/assets/images/icons/wallets/keplr.svg +9 -0
  23. package/src/assets/images/icons/wallets/leap.svg +35 -0
  24. package/src/assets/images/icons/wallets/metamask.svg +48 -0
  25. package/src/assets/images/icons/wallets/okx.svg +1 -0
  26. package/src/assets/images/icons/wallets/rabby.svg +1 -0
  27. package/src/assets/images/icons/wallets/trustwallet.svg +11 -0
  28. package/src/assets/images/icons/wallets/walletConnect.svg +11 -0
  29. package/src/assets/images/icons/wallets/wallet_icon.svg +1 -0
  30. package/src/assets/images/icons/wallets/xdefi.svg +9 -0
  31. package/src/assets/images/icons/wallets/zerion.svg +11 -0
  32. package/src/connectors/ExodusConnector.ts +6 -0
  33. package/src/connectors/LedgerLiveConnector.ts +226 -0
  34. package/src/contracts/typechain/ERC20.d.ts +441 -0
  35. package/src/contracts/typechain/factories/ERC20__factory.d.ts +56 -0
  36. package/src/contracts/typechain/factories/ERC20__factory.ts +340 -0
  37. package/src/core/constants.ts +549 -0
  38. package/src/core/externalLinks.ts +26 -0
  39. package/src/core/index.ts +1 -0
  40. package/src/core/multicall3.ts +22 -0
  41. package/src/core/numbers.ts +44 -0
  42. package/src/core/providers/CosmosProvider.tsx +55 -0
  43. package/src/core/queries/queries-keys.ts +156 -0
  44. package/src/core/queries/react-query-config.ts +13 -0
  45. package/src/core/types/components.ts +16 -0
  46. package/src/core/types/config.ts +52 -0
  47. package/src/core/types/dex.ts +31 -0
  48. package/src/core/types/error.ts +52 -0
  49. package/src/core/types/event.ts +16 -0
  50. package/src/core/types/route.ts +21 -0
  51. package/src/core/types/swap.ts +8 -0
  52. package/src/core/types/tokens.ts +30 -0
  53. package/src/core/types/transaction.ts +84 -0
  54. package/src/core/types/types.ts +37 -0
  55. package/src/core/types/wallet.ts +83 -0
  56. package/src/hooks/chains/useSquidChains.ts +66 -0
  57. package/src/hooks/cosmos/useCosmos.ts +279 -0
  58. package/src/hooks/cosmos/useCosmosForChain.ts +33 -0
  59. package/src/hooks/index.ts +32 -0
  60. package/src/hooks/navigation/useKeyboardNavigation.ts +88 -0
  61. package/src/hooks/store/useSquidStore.ts +80 -0
  62. package/src/hooks/swap/useSwap.ts +359 -0
  63. package/src/hooks/tokens/useAllTokensWithBalance.ts +157 -0
  64. package/src/hooks/tokens/useBalance.ts +180 -0
  65. package/src/hooks/tokens/useMultiChainBalance.ts +59 -0
  66. package/src/hooks/tokens/usePrices.ts +52 -0
  67. package/src/hooks/tokens/useSingleTokenPrice.ts +45 -0
  68. package/src/hooks/tokens/useSquidTokens.ts +48 -0
  69. package/src/hooks/tokens/useTokensWithBalance.ts +169 -0
  70. package/src/hooks/transaction/useEstimate.ts +397 -0
  71. package/src/hooks/transaction/useEstimatePriceImpact.ts +39 -0
  72. package/src/hooks/transaction/useExecuteTransaction.ts +440 -0
  73. package/src/hooks/transaction/useExpress.ts +46 -0
  74. package/src/hooks/transaction/useGetRoute.ts +145 -0
  75. package/src/hooks/transaction/useSingleTransaction.ts +155 -0
  76. package/src/hooks/transaction/useTransaction.ts +734 -0
  77. package/src/hooks/user/useUserParams.ts +63 -0
  78. package/src/hooks/wallet/useAddToken.ts +53 -0
  79. package/src/hooks/wallet/useAutoConnect.ts +56 -0
  80. package/src/hooks/wallet/useGnosisContext.ts +84 -0
  81. package/src/hooks/wallet/useIntegratorContext.ts +44 -0
  82. package/src/hooks/wallet/useMultiChainWallet.ts +146 -0
  83. package/src/hooks/wallet/useWallet.ts +86 -0
  84. package/src/hooks/webapp-router/useSquidRouter.ts +42 -0
  85. package/src/index.ts +5 -0
  86. package/src/provider/index.tsx +105 -0
  87. package/src/react-app-env.d.ts +2 -0
  88. package/src/services/external/analyticsService.ts +46 -0
  89. package/src/services/external/coingeckoService.ts +35 -0
  90. package/src/services/external/rpcService.ts +196 -0
  91. package/src/services/external/secretService.ts +178 -0
  92. package/src/services/index.ts +1 -0
  93. package/src/services/internal/apiService.ts +6 -0
  94. package/src/services/internal/assetsService.ts +84 -0
  95. package/src/services/internal/configService.ts +261 -0
  96. package/src/services/internal/errorService.ts +124 -0
  97. package/src/services/internal/eventService.ts +93 -0
  98. package/src/services/internal/priceService.ts +10 -0
  99. package/src/services/internal/transactionService.ts +255 -0
  100. package/src/services/internal/transactionStatusService.ts +293 -0
  101. package/src/services/internal/walletService.ts +158 -0
  102. package/src/tests/assetsService.test.ts +176 -0
  103. package/src/tests/configService.test.ts +486 -0
  104. package/src/tests/fetchSquidData.ts +43 -0
  105. package/src/tests/jest-svg-transform.ts +19 -0
  106. package/src/tests/sample.json +0 -0
  107. package/src/tests/walletService.test.ts +178 -0
  108. package/tsconfig.json +30 -0
@@ -0,0 +1,46 @@
1
+ interface EventData {
2
+ event: string;
3
+ }
4
+
5
+ declare global {
6
+ interface Window {
7
+ dataLayer: Array<EventData> | undefined;
8
+ }
9
+ }
10
+
11
+ export class AnalyticsService {
12
+ private static pushEvent(eventData: EventData): void {
13
+ if (window) {
14
+ const dataLayer = window.dataLayer || [];
15
+ const domain = window.location.hostname;
16
+
17
+ if (dataLayer && domain.includes("squidrouter.com")) {
18
+ dataLayer.push(eventData);
19
+ }
20
+ }
21
+ }
22
+
23
+ public static submitButtonPushed(): void {
24
+ this.pushEvent({ event: "submitswap_cta_clicked" });
25
+ }
26
+
27
+ public static givePermissionToUseTokenButton(): void {
28
+ this.pushEvent({ event: "permissiontoken_cta_clicked" });
29
+ }
30
+
31
+ public static settingClicked(): void {
32
+ this.pushEvent({ event: "settings_clicked" });
33
+ }
34
+
35
+ public static historyClicked(): void {
36
+ this.pushEvent({ event: "history_clicked" });
37
+ }
38
+
39
+ public static expressClicked(): void {
40
+ this.pushEvent({ event: "expressTx_clicked" });
41
+ }
42
+
43
+ public static regularClicked(): void {
44
+ this.pushEvent({ event: "regularTx_clicked" });
45
+ }
46
+ }
@@ -0,0 +1,35 @@
1
+ import { backendVersion } from "@/core/constants";
2
+ import { getQueryHeaders } from "@/services/internal/apiService";
3
+ import type { Token } from "@0xsquid/sdk/dist/types";
4
+ import axios from "axios";
5
+
6
+ interface CoingeckoPriceQuery {
7
+ apiUrl?: string;
8
+ chainId?: string;
9
+ tokenAddress?: string;
10
+ integratorId?: string;
11
+ }
12
+
13
+ export const fetchPriceForToken = async ({
14
+ apiUrl,
15
+ chainId,
16
+ tokenAddress,
17
+ integratorId,
18
+ }: CoingeckoPriceQuery): Promise<number> => {
19
+ if (chainId && tokenAddress) {
20
+ const params = {
21
+ chainId,
22
+ tokenAddress,
23
+ };
24
+ const url = `${apiUrl}/${backendVersion}/token-price`;
25
+
26
+ const response = await axios.get(url, {
27
+ params,
28
+ headers: getQueryHeaders(integratorId),
29
+ });
30
+
31
+ const result = (await response.data) as { token: Token };
32
+ return result.token.usdPrice ?? 0;
33
+ }
34
+ return 0;
35
+ };
@@ -0,0 +1,196 @@
1
+ import { ERC20__factory } from "@/contracts/typechain/factories/ERC20__factory";
2
+ import { nativeEvmTokenAddress } from "@/core/constants";
3
+ import { multicallAbi, multicallAddress } from "@/core/multicall3";
4
+ import type { TokenWithBalance } from "@/core/types/tokens";
5
+ import type { ChainData, CosmosChain, Token } from "@0xsquid/sdk/dist/types";
6
+ import { StargateClient } from "@cosmjs/stargate";
7
+ import { fetchBalance } from "@wagmi/core";
8
+ import type { BigNumber } from "ethers";
9
+ import { constants, utils } from "ethers";
10
+ import { readContracts } from "wagmi";
11
+
12
+ type ContractAddress = `0x${string}`;
13
+
14
+ /**
15
+ * Use readContracts to fetch all tokens balance in one call
16
+ * native tokens & erc20 tokens will have different abi & contract & function name
17
+ * Because it's not possible to fetch native token balance with balanceOf
18
+ * @param tokens
19
+ * @param userAddress
20
+ * @returns
21
+ */
22
+ const getTokensSupportingMultiCall = async (
23
+ tokens: Token[],
24
+ userAddress?: ContractAddress
25
+ ): Promise<TokenWithBalance[]> => {
26
+ const multicallBalances = (await readContracts({
27
+ contracts: tokens.map((t) => {
28
+ const isTokenNative = t.address.toLowerCase() === nativeEvmTokenAddress;
29
+ return {
30
+ chainId: +t.chainId,
31
+ abi: isTokenNative ? multicallAbi : ERC20__factory.abi,
32
+ address: isTokenNative
33
+ ? (multicallAddress as ContractAddress)
34
+ : (t.address as ContractAddress),
35
+ functionName: isTokenNative ? "getEthBalance" : "balanceOf",
36
+ args: [userAddress],
37
+ };
38
+ }),
39
+ allowFailure: true,
40
+ })) as BigNumber[];
41
+
42
+ return tokens.map((t, i) => ({
43
+ ...t,
44
+ balance: utils.formatUnits(
45
+ multicallBalances[i] ?? constants.Zero,
46
+ t.decimals
47
+ ),
48
+ }));
49
+ };
50
+
51
+ type FetchBalanceResult = {
52
+ decimals: number;
53
+ formatted: string;
54
+ symbol: string;
55
+ value: BigNumber;
56
+ };
57
+
58
+ /**
59
+ * Some chains don't support multicall, so we need to fetch them with Promise.all & fetchBalance
60
+ * @param tokens
61
+ * @param userAddress
62
+ * @returns
63
+ */
64
+
65
+ const getTokensWithoutMultiCall = async (
66
+ tokens: Token[],
67
+ userAddress: ContractAddress
68
+ ): Promise<TokenWithBalance[]> => {
69
+ const balances = (await Promise.all(
70
+ tokens.map(async (t) => {
71
+ let balance: FetchBalanceResult | undefined;
72
+ try {
73
+ if (t.address.toLowerCase() === nativeEvmTokenAddress) {
74
+ balance = await fetchBalance({
75
+ address: userAddress,
76
+ chainId: +t.chainId,
77
+ });
78
+ } else {
79
+ balance = await fetchBalance({
80
+ address: userAddress,
81
+ chainId: +t.chainId,
82
+ token: t.address as ContractAddress,
83
+ });
84
+ }
85
+
86
+ return balance;
87
+ } catch (error) {
88
+ return {
89
+ decimals: t.decimals,
90
+ formatted: "0",
91
+ symbol: t.symbol,
92
+ value: constants.Zero,
93
+ };
94
+ }
95
+ })
96
+ )) as FetchBalanceResult[];
97
+
98
+ return tokens.map((t, i) => ({
99
+ ...t,
100
+ balance: utils.formatUnits(balances[i].value, t.decimals),
101
+ }));
102
+ };
103
+
104
+ export const getAllEvmTokensBalance = async (
105
+ evmTokens: Token[],
106
+ userAddress: string
107
+ ): Promise<TokenWithBalance[]> => {
108
+ // Some tokens don't support multicall, so we need to fetch them with Promise.all
109
+ // TODO: Once we support multicall on all chains, we can remove this split
110
+ const chainWithoutMulticall = [314, 3141]; // Filecoin, & Filecoin testnet
111
+ const splittedTokensByMultiCallSupport = evmTokens.reduce(
112
+ (acc, token) => {
113
+ if (chainWithoutMulticall.includes(+token.chainId)) {
114
+ acc[0].push(token);
115
+ } else {
116
+ acc[1].push(token);
117
+ }
118
+ return acc;
119
+ },
120
+ [[], []] as Token[][]
121
+ );
122
+
123
+ const tokensNotSupportingMulticall = splittedTokensByMultiCallSupport[0];
124
+ const tokensSupportingMulticall = splittedTokensByMultiCallSupport[1];
125
+
126
+ const tokensMulticall = await getTokensSupportingMultiCall(
127
+ tokensSupportingMulticall,
128
+ userAddress as ContractAddress
129
+ );
130
+
131
+ const tokensNotMultiCall = await getTokensWithoutMultiCall(
132
+ tokensNotSupportingMulticall,
133
+ userAddress as ContractAddress
134
+ );
135
+
136
+ return [...tokensMulticall, ...tokensNotMultiCall];
137
+ };
138
+
139
+ /**
140
+ * We'll get the current block of a given RPC to see if we can query it
141
+ * Without getting CORS error or any other error
142
+ * @param rpc
143
+ * @returns
144
+ */
145
+ const testCosmosRpc = async (rpc: string): Promise<boolean> => {
146
+ let rpcIsValid = false;
147
+ try {
148
+ const client = await StargateClient.connect(rpc);
149
+ const block = await client.getBlock();
150
+ rpcIsValid = !!block.id;
151
+ } catch (error) {
152
+ rpcIsValid = false;
153
+ }
154
+ return rpcIsValid;
155
+ };
156
+
157
+ export const getWorkingCosmosRpcUrl = async (
158
+ chainData: ChainData
159
+ ): Promise<string> => {
160
+ const rpcList =
161
+ (chainData as CosmosChain & { rpcList: string[] }).rpcList ?? chainData.rpc
162
+ ? [chainData.rpc]
163
+ : [];
164
+
165
+ // if rpcList is empty, use the default rpc
166
+ if (rpcList.length === 0) {
167
+ try {
168
+ const isValid = await testCosmosRpc(chainData.rpc);
169
+ if (isValid) {
170
+ return chainData.rpc;
171
+ }
172
+ } catch (error) {
173
+ console.log(
174
+ `Error fetching rpc url: ${chainData.rpc} - Error: ${(error as any)?.toString()}`
175
+ );
176
+ }
177
+ }
178
+
179
+ // if rpcList is not empty, try to fetch each rpc until we find a valid one
180
+ for (const rpc of rpcList) {
181
+ try {
182
+ // eslint-disable-next-line no-await-in-loop
183
+ const isValid = await testCosmosRpc(rpc);
184
+ if (isValid) {
185
+ return rpc;
186
+ }
187
+ } catch (error) {
188
+ console.log(
189
+ `Error fetching rpc url: ${chainData.rpc} - Error: ${(error as any)?.toString()}`
190
+ );
191
+ }
192
+ }
193
+
194
+ // In the case that all rpcs are invalid, return the default rpc anyway
195
+ return chainData.rpc;
196
+ };
@@ -0,0 +1,178 @@
1
+ import type { TokenWithBalance } from "@/core/types/tokens";
2
+ import type { TypedWindow } from "@/core/types/wallet";
3
+ import type { ChainData, CosmosChain, Token } from "@0xsquid/squid-types";
4
+ import { StargateClient } from "@cosmjs/stargate";
5
+ import type { Keplr } from "@keplr-wallet/types";
6
+ import { formatUnits } from "ethers/lib/utils.js";
7
+ import { SecretNetworkClient } from "secretjs";
8
+
9
+ /**
10
+ * Fetch secret network token balance
11
+ * Using the permit signature, see permit function for more details
12
+ * @param secretJS
13
+ * @param contract
14
+ * @param chainId
15
+ * @param walletAddress
16
+ * @param permit
17
+ * @returns
18
+ */
19
+ export const getTokenBalance = async (
20
+ secretJS: SecretNetworkClient,
21
+ contract: { address: string; codeHash: string },
22
+ permit: any
23
+ ) => {
24
+ if (permit) {
25
+ const msg = {
26
+ balance: {},
27
+ };
28
+
29
+ const result = await secretJS.query.compute.queryContract({
30
+ contract_address: contract.address,
31
+ code_hash: contract.codeHash,
32
+ query: {
33
+ with_permit: {
34
+ query: msg,
35
+ permit,
36
+ },
37
+ },
38
+ });
39
+ return result;
40
+ }
41
+ return -1;
42
+ };
43
+
44
+ export const getPermit = async (
45
+ chainId: string,
46
+ contracts: any[],
47
+ address: string
48
+ ) => {
49
+ const contractsString = contracts.join("_");
50
+ const permKey = `perm_${chainId}_${contractsString}_${address}`;
51
+ let permit: any;
52
+
53
+ const permitStored = window.localStorage.getItem(permKey);
54
+ if (permitStored) permit = JSON.parse(permitStored);
55
+
56
+ // Not able to fetch permit signature from local storage,
57
+ // Ask user to sign message
58
+ if (!permit) {
59
+ try {
60
+ const result = await (window as TypedWindow).keplr.signAmino(
61
+ chainId,
62
+ address,
63
+ {
64
+ chain_id: chainId,
65
+ account_number: "0",
66
+ sequence: "0",
67
+ fee: {
68
+ amount: [{ denom: "uscrt", amount: "0" }],
69
+ gas: "1",
70
+ },
71
+ msgs: [
72
+ {
73
+ type: "query_permit",
74
+ value: {
75
+ permit_name: "secret-bridge-balance",
76
+ allowed_tokens: contracts,
77
+ permissions: ["balance"],
78
+ },
79
+ },
80
+ ],
81
+ memo: "",
82
+ },
83
+ {
84
+ preferNoSetFee: true,
85
+ preferNoSetMemo: true,
86
+ }
87
+ );
88
+ permit = {
89
+ params: {
90
+ permit_name: "secret-bridge-balance",
91
+ allowed_tokens: contracts,
92
+ chain_id: chainId,
93
+ permissions: ["balance"],
94
+ },
95
+ signature: result.signature,
96
+ };
97
+ window.localStorage.setItem(permKey, JSON.stringify(permit));
98
+ } catch (err) {
99
+ console.log("--- PERMIT ERROR ---");
100
+ console.log(err);
101
+ }
102
+ }
103
+ return permit;
104
+ };
105
+
106
+ /**
107
+ * Fetches the secret balance of the user
108
+ * This has a different logic than the other balances because Secret network hides the balance of the user by design
109
+ * So we need to fetch the balance in a different way
110
+ */
111
+ export const SECRET_CHAIN_ID = "secret-4";
112
+
113
+ export const fetchAllSecretBalances = async (
114
+ chainData: ChainData,
115
+ userAddress: string,
116
+ secretTokens: (Token & { codeHash?: string })[],
117
+ keplr?: Keplr
118
+ ): Promise<TokenWithBalance[]> => {
119
+ if (!keplr) return [];
120
+ // Enables app to utilize keplr's secret utilities
121
+ await keplr.enable(SECRET_CHAIN_ID);
122
+ // Create a client that handles the query encryption
123
+ const client = new SecretNetworkClient({
124
+ url: (chainData as CosmosChain).rest,
125
+ chainId: SECRET_CHAIN_ID,
126
+ wallet: keplr.getOfflineSignerOnlyAmino(SECRET_CHAIN_ID),
127
+ encryptionUtils: keplr.getEnigmaUtils(SECRET_CHAIN_ID),
128
+ walletAddress: userAddress,
129
+ });
130
+
131
+ // Get secret tokens
132
+
133
+ const permit = await getPermit(
134
+ SECRET_CHAIN_ID,
135
+ secretTokens.map((st) => st.address),
136
+ userAddress
137
+ );
138
+
139
+ // Fetching all balances in parallel
140
+ const privateTokens = await Promise.all(
141
+ secretTokens
142
+ .filter((t) => !!t.codeHash)
143
+ .map(async (token) => {
144
+ const result = (await getTokenBalance(
145
+ client,
146
+ {
147
+ address: token.address,
148
+ codeHash: token.codeHash ?? "",
149
+ },
150
+ permit
151
+ )) as { balance: { amount: string } };
152
+
153
+ return {
154
+ ...token,
155
+ balance: formatUnits(result.balance.amount, token?.decimals),
156
+ } as TokenWithBalance;
157
+ })
158
+ );
159
+
160
+ // Use Stargate getBalance for SCRT
161
+ const stargateClient = await StargateClient.connect(chainData.rpc);
162
+ const nativeSecretToken = secretTokens.find((t) => t.address === "uscrt");
163
+
164
+ const publicTokenBalance = await stargateClient.getBalance(
165
+ userAddress,
166
+ "uscrt"
167
+ );
168
+
169
+ const publicTokenWithBalance = {
170
+ ...nativeSecretToken,
171
+ balance: formatUnits(
172
+ publicTokenBalance.amount,
173
+ nativeSecretToken?.decimals
174
+ ),
175
+ } as TokenWithBalance;
176
+
177
+ return [...privateTokens, publicTokenWithBalance];
178
+ };
@@ -0,0 +1 @@
1
+ export * from "./internal/walletService";
@@ -0,0 +1,6 @@
1
+ export const getQueryHeaders = (integratorId?: string, requestId?: string) => {
2
+ return {
3
+ ...(integratorId ? { "X-Integrator-Id": integratorId } : {}),
4
+ ...(requestId ? { "X-Request-Id": requestId } : {}),
5
+ };
6
+ };
@@ -0,0 +1,84 @@
1
+ import type { AppConfig } from "@/core/types/config";
2
+ import type { ChainData, Token } from "@0xsquid/squid-types";
3
+
4
+ export const shareSubgraphId = (token1: Token, token2: Token) => {
5
+ return Boolean(
6
+ token1?.subGraphIds?.some((sgi) => !!token2?.subGraphIds?.includes(sgi)) ||
7
+ token2?.subGraphIds?.some((sgi) => !!token1?.subGraphIds?.includes(sgi))
8
+ );
9
+ };
10
+
11
+ /**
12
+ * Check if `tokenToCheck` shares any subgraph id with the tokens being compared
13
+ * If any of the tokens being compared shares a subgraph id with `tokenToCheck`, it will be sorted first
14
+ * @param a first token being compared
15
+ * @param b second token being compared
16
+ * @param tokenToCheck the token to check subgraph ids against
17
+ */
18
+ export function sortTokensBySharedSubgraphIds({
19
+ a,
20
+ b,
21
+ tokenToCheck,
22
+ }: {
23
+ a: Token;
24
+ b: Token;
25
+ tokenToCheck: Token;
26
+ }): -1 | 0 | 1 {
27
+ const tokenToCheckSharesIdsWithA = shareSubgraphId(a, tokenToCheck);
28
+
29
+ const tokenToCheckSharesIdsWithB = shareSubgraphId(b, tokenToCheck);
30
+
31
+ if (tokenToCheckSharesIdsWithA && !tokenToCheckSharesIdsWithB) {
32
+ return -1;
33
+ }
34
+
35
+ if (!tokenToCheckSharesIdsWithA && tokenToCheckSharesIdsWithB) {
36
+ return 1;
37
+ }
38
+
39
+ return 0;
40
+ }
41
+
42
+ /**
43
+ * Filter chains based on provided config
44
+ *
45
+ * Filter order:
46
+ * 1. Chains that are not disabled or coming soon
47
+ * 2. Disabled chains
48
+ * 3. Coming soon chains
49
+ */
50
+ export function filterChains({
51
+ chains,
52
+ config,
53
+ direction,
54
+ }: {
55
+ chains: ChainData[];
56
+ config: Pick<AppConfig, "disabledChains" | "comingSoonChainIds">;
57
+ direction: "from" | "to";
58
+ }): ChainData[] {
59
+ // filter coming soon chains
60
+ const comingSoonChains = chains.filter((c) =>
61
+ config.comingSoonChainIds?.includes(c.chainId)
62
+ );
63
+
64
+ // map direction to be a key of config.disabledChains object
65
+ const parsedDirection = direction === "from" ? "source" : "destination";
66
+ // get disabled chains for the direction provided
67
+ const disabledChainsOnDirection = config.disabledChains?.[parsedDirection];
68
+
69
+ // filter disabled chains
70
+ const disabledChains = chains.filter(
71
+ (c) =>
72
+ disabledChainsOnDirection?.includes(c.chainId) &&
73
+ !config.comingSoonChainIds?.includes(c.chainId)
74
+ );
75
+
76
+ // filter chains that are not disabled or coming soon
77
+ const filteredChains = chains.filter(
78
+ (c) =>
79
+ !config.comingSoonChainIds?.includes(c.chainId) &&
80
+ !disabledChainsOnDirection?.includes(c.chainId)
81
+ );
82
+
83
+ return [...filteredChains, ...disabledChains, ...comingSoonChains];
84
+ }