@xswap-link/sdk 0.0.13 → 0.1.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 (81) hide show
  1. package/.github/workflows/main.yml +1 -1
  2. package/.github/workflows/publish.yml +1 -1
  3. package/.prettierrc +7 -0
  4. package/CHANGELOG.md +12 -1
  5. package/README.md +23 -14
  6. package/dist/index.css +1012 -0
  7. package/dist/index.d.mts +209 -52
  8. package/dist/index.d.ts +209 -52
  9. package/dist/index.js +33963 -88
  10. package/dist/index.mjs +33949 -76
  11. package/package.json +8 -2
  12. package/postcss.config.js +3 -0
  13. package/src/components/Alert/index.tsx +9 -0
  14. package/src/components/Skeleton/index.tsx +10 -0
  15. package/src/components/TxConfigForm/Form.tsx +567 -0
  16. package/src/components/TxConfigForm/History.tsx +159 -0
  17. package/src/components/TxConfigForm/HistoryCard.tsx +209 -0
  18. package/src/components/TxConfigForm/TokenPicker.tsx +165 -0
  19. package/src/components/TxConfigForm/index.jsx +100 -0
  20. package/src/components/global.css +34 -0
  21. package/src/components/global.d.ts +6 -0
  22. package/src/components/icons/ArrowRightIcon.tsx +11 -0
  23. package/src/components/icons/ArrowUpRightIcon.tsx +11 -0
  24. package/src/components/icons/CheckIcon.tsx +11 -0
  25. package/src/components/icons/ChevronDownIcon.tsx +15 -0
  26. package/src/components/icons/ChevronUpIcon.tsx +15 -0
  27. package/src/components/icons/CircularProgressIcon.tsx +24 -0
  28. package/src/components/icons/CloseIcon.tsx +15 -0
  29. package/src/components/icons/CoinsIcon.tsx +15 -0
  30. package/src/components/icons/DownArrorIcon.tsx +17 -0
  31. package/src/components/icons/HistoryIcon.tsx +13 -0
  32. package/src/components/icons/HourGlassIcon.tsx +11 -0
  33. package/src/components/icons/PercentageIcon.tsx +29 -0
  34. package/src/components/icons/SearchIcon.tsx +15 -0
  35. package/src/components/icons/XMarkIcon.tsx +11 -0
  36. package/src/components/icons/index.ts +14 -0
  37. package/src/components/index.ts +3 -0
  38. package/src/constants/index.ts +6 -5
  39. package/src/contracts/abi/BatchQuery.json +52 -0
  40. package/src/contracts/abi/index.ts +2 -0
  41. package/src/contracts/addresses.ts +34 -0
  42. package/src/contracts/index.ts +1 -0
  43. package/src/hooks/index.ts +1 -0
  44. package/src/hooks/useDebounce.tsx +21 -0
  45. package/src/index.ts +6 -0
  46. package/src/models/Addresses.ts +12 -0
  47. package/src/models/Route.ts +17 -5
  48. package/src/models/TokenData.ts +45 -0
  49. package/src/models/TransactionHistory.ts +48 -0
  50. package/src/models/XSwapConfig.ts +3 -0
  51. package/src/models/forms/TxConfigFormData.ts +8 -0
  52. package/src/models/forms/index.ts +1 -0
  53. package/src/models/index.ts +6 -6
  54. package/src/models/integrations/GenerateStakingCallsParams.ts +8 -0
  55. package/src/models/integrations/index.ts +1 -0
  56. package/src/models/payloads/GetPricesPayload.ts +4 -0
  57. package/src/models/payloads/GetRoutePayload.ts +1 -3
  58. package/src/models/payloads/GetSwapTxPayload.ts +8 -0
  59. package/src/models/payloads/index.ts +2 -0
  60. package/src/services/api.ts +46 -64
  61. package/src/services/index.ts +1 -0
  62. package/src/services/integrations/customCalls/index.ts +1 -0
  63. package/src/services/integrations/customCalls/staking.ts +83 -0
  64. package/src/services/integrations/index.ts +2 -0
  65. package/src/services/integrations/transactions.ts +30 -0
  66. package/src/utils/contracts.ts +153 -11
  67. package/src/utils/index.ts +49 -1
  68. package/src/utils/numbers.ts +47 -0
  69. package/src/utils/strings.ts +6 -0
  70. package/tailwind.config.js +14 -0
  71. package/test/api.test.ts +1 -1
  72. package/tsconfig.json +10 -1
  73. package/xswap.config.ts +18 -0
  74. package/index.ts +0 -5
  75. package/src/models/ApiOverrides.ts +0 -3
  76. package/src/models/Chain.ts +0 -20
  77. package/src/models/Prices.ts +0 -9
  78. package/src/models/Token.ts +0 -10
  79. package/src/models/XSwapFee.ts +0 -4
  80. package/src/models/XSwapFees.ts +0 -7
  81. package/src/utils/bigNumbers.ts +0 -7
@@ -1,31 +1,33 @@
1
+ import xSwapConfig from "../../xswap.config";
1
2
  import {
2
- ApiOverrides,
3
3
  BridgeToken,
4
4
  Chain,
5
5
  Ecosystem,
6
+ GetPricesPayload,
6
7
  GetRoutePayload,
7
8
  Route,
8
9
  Token,
9
- } from "../models";
10
- import { DEFAULT_API_URL } from "../constants";
10
+ TokenPrices,
11
+ TransactionHistory,
12
+ } from "@src/models";
11
13
 
12
14
  async function _sendRequest<T>(
13
15
  urlPath: string,
14
- options: RequestInit,
15
- overrides?: ApiOverrides
16
+ options?: RequestInit,
16
17
  ): Promise<T> {
17
- const apiUrl = overrides?.apiUrl || DEFAULT_API_URL;
18
- const response = await fetch(`${apiUrl}${urlPath}`, {
19
- ...options,
18
+ const response = await fetch(`${xSwapConfig.apiUrl}${urlPath}`, {
19
+ method: "GET",
20
20
  headers: {
21
21
  "Content-Type": "application/json",
22
- ...options.headers,
22
+ "Cache-Control": "no-cache",
23
+ ...options?.headers,
23
24
  },
25
+ ...options,
24
26
  });
25
27
 
26
28
  if (!response.ok) {
27
29
  throw new Error(
28
- `API request failed with status ${response.status}: ${response.statusText}`
30
+ `API request failed with status ${response.status}: ${response.statusText}`,
29
31
  );
30
32
  }
31
33
 
@@ -35,61 +37,37 @@ async function _sendRequest<T>(
35
37
  /**
36
38
  * Get swap route based on provided criteria.
37
39
  * @param payload required
38
- * @param overrides optional - e.g. {apiUrl}
39
40
  */
40
- export async function getRoute(
41
- payload: GetRoutePayload,
42
- overrides?: ApiOverrides
43
- ): Promise<Route> {
44
- return _sendRequest<Route>(
45
- "/route",
46
- {
47
- method: "POST",
48
- body: JSON.stringify(payload),
49
- },
50
- overrides
51
- );
41
+ export async function getRoute(payload: GetRoutePayload): Promise<Route> {
42
+ return _sendRequest<Route>("/route", {
43
+ method: "POST",
44
+ body: JSON.stringify(payload),
45
+ });
52
46
  }
53
47
 
54
48
  /**
55
49
  * GET chains based on provided criteria.
56
50
  * @param ecosystem optional
57
- * @param overrides optional - e.g. {apiUrl}
58
51
  */
59
- export async function getChains(
60
- ecosystem?: Ecosystem,
61
- overrides?: ApiOverrides
62
- ): Promise<Chain[]> {
63
- const data = { ecosystem };
64
-
65
- return _sendRequest<Chain[]>(
66
- `/chains?data=${JSON.stringify(data)}`,
67
- {
68
- method: "GET",
69
- },
70
- overrides
71
- );
52
+ export async function getChains(ecosystem?: Ecosystem): Promise<Chain[]> {
53
+ return _sendRequest<Chain[]>(`/chains?data=${JSON.stringify({ ecosystem })}
54
+ `);
72
55
  }
73
56
 
74
57
  /**
75
58
  * GET chain data based on provided criteria.
76
59
  * @param chainId
77
60
  * @param ecosystem optional - Default: {@link DEFAULT_ECOSYSTEM}
78
- * @param overrides optional - e.g. {apiUrl}
79
61
  */
80
62
  export async function getChainData(
81
63
  chainId?: string,
82
64
  ecosystem?: Ecosystem,
83
- overrides?: ApiOverrides
84
65
  ): Promise<Chain> {
85
- const data = { chainId, ecosystem };
86
-
87
66
  return _sendRequest<Chain>(
88
- `/chains?data=${JSON.stringify(data)}`,
89
- {
90
- method: "GET",
91
- },
92
- overrides
67
+ `/chains?data=${JSON.stringify({
68
+ chainId,
69
+ ecosystem,
70
+ })}`,
93
71
  );
94
72
  }
95
73
 
@@ -98,33 +76,37 @@ export async function getChainData(
98
76
  * @param chainId required
99
77
  * @param address optional
100
78
  * @param ecosystem optional but {@link DEFAULT_ECOSYSTEM} will be considered
101
- * @param overrides optional - e.g. {apiUrl}
102
79
  */
103
80
  export async function getTokens(
104
81
  chainId: string,
105
82
  address?: string,
106
83
  ecosystem?: Ecosystem,
107
- overrides?: ApiOverrides
108
84
  ): Promise<Token[]> {
109
- const data = { chainId, address, ecosystem };
110
-
111
85
  return _sendRequest<Token[]>(
112
- `/tokens?data=${JSON.stringify(data)}`,
113
- {
114
- method: "GET",
115
- },
116
- overrides
86
+ `/tokens?data=${JSON.stringify({
87
+ chainId,
88
+ address,
89
+ ecosystem,
90
+ })}`,
117
91
  );
118
92
  }
119
93
 
120
- export async function getBridgeTokens(
121
- overrides?: ApiOverrides
122
- ): Promise<BridgeToken[]> {
123
- return _sendRequest<BridgeToken[]>(
124
- `/bridgeTokens`,
125
- {
126
- method: "GET",
127
- },
128
- overrides
94
+ export async function getBridgeTokens(): Promise<BridgeToken[]> {
95
+ return _sendRequest<BridgeToken[]>(`/bridgeTokens`);
96
+ }
97
+
98
+ export async function getHistory(payload: { walletAddress: string }) {
99
+ return await _sendRequest<TransactionHistory>(
100
+ `/history?${new URLSearchParams({
101
+ data: JSON.stringify(payload),
102
+ })}`,
103
+ );
104
+ }
105
+
106
+ export async function getPrices(payload: GetPricesPayload) {
107
+ return await _sendRequest<TokenPrices>(
108
+ `/tokenPrices?${new URLSearchParams({
109
+ data: JSON.stringify(payload),
110
+ })}`,
129
111
  );
130
112
  }
@@ -1 +1,2 @@
1
1
  export * from "./api";
2
+ export * from "./integrations";
@@ -0,0 +1 @@
1
+ export * from "./staking";
@@ -0,0 +1,83 @@
1
+ import { ethers } from "ethers";
2
+ import {
3
+ ContractCall,
4
+ GenerateStakingCallsParams,
5
+ XSwapCallType,
6
+ } from "@src/models";
7
+ import {
8
+ findPlaceholderIndex,
9
+ generateUniqueRandomBigNumber,
10
+ IERC20,
11
+ replaceNull,
12
+ } from "@src/utils";
13
+ import { ERC20Abi } from "@src/contracts";
14
+
15
+ export const generateStakingCalls = ({
16
+ token,
17
+ staking,
18
+ stakingAbi,
19
+ stakingFunName,
20
+ stakingFunParams,
21
+ }: GenerateStakingCallsParams): ContractCall[] => {
22
+ const flatStakingFunParams = stakingFunParams.flat(Infinity);
23
+
24
+ if (flatStakingFunParams.filter((param) => param === null).length !== 1) {
25
+ throw new Error(
26
+ "Exactly 1 'null' value should be provided in 'funParams' in order to override token balance",
27
+ );
28
+ }
29
+
30
+ const randomBigNumber = generateUniqueRandomBigNumber(
31
+ 32,
32
+ flatStakingFunParams,
33
+ );
34
+
35
+ const modifiedStakingFunParams = replaceNull(
36
+ stakingFunParams,
37
+ randomBigNumber,
38
+ );
39
+
40
+ const approveFunParams = [staking, randomBigNumber];
41
+ const stakingApproveCall: ContractCall = {
42
+ callType: XSwapCallType.FULL_TOKEN_BALANCE,
43
+ target: token,
44
+ callData: IERC20.encodeFunctionData("approve", approveFunParams),
45
+ payload: ethers.utils.defaultAbiCoder.encode(
46
+ ["address", "uint256"],
47
+ [
48
+ token,
49
+ findPlaceholderIndex(
50
+ JSON.stringify(ERC20Abi),
51
+ "approve",
52
+ approveFunParams,
53
+ randomBigNumber,
54
+ ),
55
+ ],
56
+ ),
57
+ value: "0",
58
+ };
59
+
60
+ const stakingCall: ContractCall = {
61
+ callType: XSwapCallType.FULL_TOKEN_BALANCE,
62
+ target: staking,
63
+ callData: new ethers.utils.Interface(stakingAbi).encodeFunctionData(
64
+ stakingFunName,
65
+ modifiedStakingFunParams,
66
+ ),
67
+ payload: ethers.utils.defaultAbiCoder.encode(
68
+ ["address", "uint256"],
69
+ [
70
+ token,
71
+ findPlaceholderIndex(
72
+ stakingAbi,
73
+ stakingFunName,
74
+ modifiedStakingFunParams,
75
+ randomBigNumber,
76
+ ),
77
+ ],
78
+ ),
79
+ value: "0",
80
+ };
81
+
82
+ return [stakingApproveCall, stakingCall];
83
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./customCalls";
2
+ export * from "./transactions";
@@ -0,0 +1,30 @@
1
+ import {
2
+ Chain,
3
+ GetSwapTxPayload,
4
+ Transactions,
5
+ Web3Environment,
6
+ } from "@src/models";
7
+ import { getChains } from "@src/services";
8
+ import { openTxConfigForm } from "@src/components";
9
+
10
+ export const getSwapTx = async ({
11
+ dstChain,
12
+ dstToken,
13
+ customContractCalls = [],
14
+ desc,
15
+ }: GetSwapTxPayload): Promise<Transactions> => {
16
+ const supportedChains: Chain[] = (await getChains()).filter(
17
+ ({ web3Environment, swapSupported }) =>
18
+ web3Environment === Web3Environment.MAINNET && swapSupported,
19
+ );
20
+
21
+ const route = await openTxConfigForm({
22
+ dstChainId: dstChain,
23
+ dstTokenAddr: dstToken,
24
+ customContractCalls,
25
+ desc,
26
+ supportedChains,
27
+ });
28
+
29
+ return route.transactions;
30
+ };
@@ -1,19 +1,161 @@
1
- import { BigNumberish, ethers } from "ethers";
2
- import { ERC20Abi } from "../contracts";
3
- import { safeBigNumberFrom } from "./bigNumbers";
1
+ import { BigNumber, BigNumberish, ethers } from "ethers";
2
+ import { TransactionRequest } from "@ethersproject/providers";
3
+ import { safeBigNumberFrom } from "./numbers";
4
+ import { ADDRESSES, BatchQueryAbi, ERC20Abi } from "@src/contracts";
5
+ import { Chain, TokenBalances } from "@src/models";
6
+ import { chunkArray } from "@src/utils";
7
+ import { BALANCES_CHUNK_SIZE } from "@src/constants";
4
8
 
5
- const erc20Interface = new ethers.utils.Interface(ERC20Abi);
9
+ export const IERC20 = new ethers.utils.Interface(ERC20Abi);
10
+
11
+ export const getBalanceOf = async (
12
+ wallet: string,
13
+ token: string,
14
+ rpcUrl: string,
15
+ ): Promise<string> => {
16
+ const provider = ethers.getDefaultProvider(rpcUrl);
17
+
18
+ if (token === ethers.constants.AddressZero) {
19
+ return ethers.utils.formatEther(await provider.getBalance(wallet));
20
+ }
21
+
22
+ const contract = new ethers.Contract(token, ERC20Abi, provider);
23
+ return ethers.utils.formatUnits(
24
+ await contract.balanceOf(wallet),
25
+ await contract.decimals(),
26
+ );
27
+ };
28
+
29
+ export const getBalances = async (
30
+ chain: Chain,
31
+ wallet: string,
32
+ ): Promise<TokenBalances> => {
33
+ return {
34
+ ...(await getNativeBalance(chain, wallet)),
35
+ ...(await getErc20Balances(chain, wallet)),
36
+ };
37
+ };
38
+
39
+ const getNativeBalance = async (
40
+ chain: Chain,
41
+ wallet: string,
42
+ ): Promise<TokenBalances> => {
43
+ const native = chain.tokens.find(
44
+ ({ address }) => address === ethers.constants.AddressZero,
45
+ );
46
+
47
+ if (native) {
48
+ const provider = ethers.getDefaultProvider(chain.publicRpcUrls[0]);
49
+ const balance = await provider.getBalance(wallet);
50
+ return {
51
+ [native.address]: balance,
52
+ };
53
+ }
54
+ return {};
55
+ };
56
+
57
+ const getErc20Balances = async (
58
+ chain: Chain,
59
+ wallet: string,
60
+ ): Promise<TokenBalances> => {
61
+ const erc20Tokens = chain.tokens.filter(
62
+ ({ address }) => address !== ethers.constants.AddressZero,
63
+ );
64
+ const tokenChunks = chunkArray(erc20Tokens, BALANCES_CHUNK_SIZE);
65
+ const promises = tokenChunks.map(async (tokenChunk) => {
66
+ const tokenAddresses = tokenChunk.map((token) => token.address);
67
+ const calldatas = tokenChunk.map(() =>
68
+ IERC20.encodeFunctionData("balanceOf", [wallet]),
69
+ );
70
+
71
+ const contractAddress = ADDRESSES[chain.chainId]?.BatchQuery;
72
+ const rpcUrl = chain.publicRpcUrls[0];
73
+ if (contractAddress && rpcUrl) {
74
+ const contract = new ethers.Contract(
75
+ contractAddress,
76
+ BatchQueryAbi,
77
+ ethers.getDefaultProvider(rpcUrl),
78
+ );
79
+ return await contract["batchQuery"](tokenAddresses, calldatas);
80
+ }
81
+ return Promise.resolve();
82
+ });
83
+
84
+ const tokenBalances: BigNumber[] = (await Promise.all(promises))
85
+ .flat()
86
+ .map(
87
+ (encodedBalance) =>
88
+ ethers.utils.defaultAbiCoder.decode(["uint256"], encodedBalance)[0],
89
+ );
90
+
91
+ const balances: TokenBalances = {};
92
+
93
+ erc20Tokens.forEach((token, index) => {
94
+ balances[token.address] = tokenBalances[index];
95
+ });
96
+ return balances;
97
+ };
6
98
 
7
99
  export const generateApproveTxData = (
8
100
  tokenAddress: string,
9
101
  spender: string,
10
- amount: BigNumberish
102
+ amount: BigNumberish,
103
+ ): TransactionRequest | undefined => {
104
+ return tokenAddress !== ethers.constants.AddressZero
105
+ ? {
106
+ to: tokenAddress,
107
+ value: safeBigNumberFrom("0"),
108
+ data: IERC20.encodeFunctionData("approve", [spender, amount]),
109
+ }
110
+ : undefined;
111
+ };
112
+
113
+ /**
114
+ * Calculate param's value offset within the encoded function's bytecode.
115
+ * @param abi
116
+ * @param funName
117
+ * @param funParams
118
+ * @param placeholderValue
119
+ */
120
+ export const findPlaceholderIndex = (
121
+ abi: string,
122
+ funName: string,
123
+ // eslint-disable-next-line
124
+ funParams: any[],
125
+ placeholderValue: BigNumber,
11
126
  ) => {
12
- const data = erc20Interface.encodeFunctionData("approve", [spender, amount]);
127
+ if (
128
+ funParams.flat(Infinity).filter((param) => param === placeholderValue)
129
+ .length !== 1
130
+ ) {
131
+ throw new Error("Random placeholder value must be provided and unique.");
132
+ }
13
133
 
14
- return {
15
- to: tokenAddress,
16
- value: safeBigNumberFrom("0"),
17
- data,
18
- };
134
+ const iface = new ethers.utils.Interface(abi);
135
+ const functionFragment = iface.getFunction(funName);
136
+
137
+ if (!functionFragment) {
138
+ throw new Error(`Can't find function "${funName}" in provided ABI.`);
139
+ }
140
+
141
+ const encodedFunData = iface.encodeFunctionData(functionFragment, funParams);
142
+
143
+ // Remove the 4-byte selector
144
+ const paramData = encodedFunData.slice(10);
145
+
146
+ // Split into 32-byte (64 hex characters) chunks
147
+ const chunks: string[] = [];
148
+ for (let i = 0; i < paramData.length; i += 64) {
149
+ chunks.push(paramData.slice(i, i + 64));
150
+ }
151
+
152
+ // Find the index of the chunk containing the random value
153
+ const searchValue = placeholderValue.toHexString().slice(2).padStart(64, "0");
154
+ const result = chunks.findIndex((chunk) => chunk === searchValue);
155
+
156
+ if (result === -1) {
157
+ throw new Error("Randomized parameter not found in the encoded data.");
158
+ }
159
+
160
+ return result;
19
161
  };
@@ -1,2 +1,50 @@
1
- export * from "./bigNumbers";
2
1
  export * from "./contracts";
2
+ export * from "./numbers";
3
+ export * from "./strings";
4
+
5
+ // eslint-disable-next-line
6
+ export const replaceNull = (values: any[], newValue: any) => {
7
+ const modifiedValues = [...values];
8
+ for (let i = 0; i < modifiedValues.length; i++) {
9
+ if (Array.isArray(modifiedValues[i])) {
10
+ modifiedValues[i] = replaceNull(modifiedValues[i], newValue);
11
+ } else {
12
+ if (modifiedValues[i] === null) {
13
+ modifiedValues[i] = newValue;
14
+ }
15
+ }
16
+ }
17
+ return modifiedValues;
18
+ };
19
+
20
+ export const deepMergeObjects = (
21
+ // eslint-disable-next-line
22
+ obj1: Record<string, any>,
23
+ // eslint-disable-next-line
24
+ obj2: Record<string, any>,
25
+ ) => {
26
+ for (const key in obj2) {
27
+ if (obj2.hasOwnProperty(key)) {
28
+ if (
29
+ obj1.hasOwnProperty(key) &&
30
+ typeof obj1[key] === "object" &&
31
+ typeof obj2[key] === "object"
32
+ ) {
33
+ deepMergeObjects(obj1[key], obj2[key]);
34
+ } else {
35
+ obj1[key] = obj2[key];
36
+ }
37
+ }
38
+ }
39
+ return { ...obj1 };
40
+ };
41
+
42
+ // eslint-disable-next-line
43
+ export const chunkArray = (array: any[], chunkSize: number): any[][] => {
44
+ // eslint-disable-next-line
45
+ const result: any[][] = [];
46
+ for (let i = 0; i < array.length; i += chunkSize) {
47
+ result.push(array.slice(i, i + chunkSize));
48
+ }
49
+ return result;
50
+ };
@@ -0,0 +1,47 @@
1
+ import { BigNumber as BigNumberJS } from "bignumber.js";
2
+ import { BigNumber, utils } from "ethers";
3
+
4
+ export const safeBigNumberFrom = (value: string) => {
5
+ BigNumberJS.config({ DECIMAL_PLACES: 0 });
6
+ return BigNumber.from(new BigNumberJS(value).div(1).toFixed());
7
+ };
8
+
9
+ export const weiToHumanReadable = ({
10
+ amount,
11
+ decimals,
12
+ precisionFractionalPlaces,
13
+ prettifySmallNumber = false,
14
+ }: {
15
+ amount: string;
16
+ decimals: number;
17
+ precisionFractionalPlaces: number;
18
+ prettifySmallNumber?: boolean;
19
+ }): string => {
20
+ const decimalsFactor = Math.pow(10, decimals);
21
+
22
+ BigNumberJS.config({ DECIMAL_PLACES: precisionFractionalPlaces });
23
+
24
+ const res = new BigNumberJS(amount).div(decimalsFactor).toFixed();
25
+ if (prettifySmallNumber && res === "0" && amount !== "0") {
26
+ return `<${(1 / 10 ** precisionFractionalPlaces).toFixed(
27
+ precisionFractionalPlaces,
28
+ )}`;
29
+ }
30
+ return res;
31
+ };
32
+
33
+ export const generateRandomBigNumber = (length: number) => {
34
+ return BigNumber.from(utils.randomBytes(length));
35
+ };
36
+
37
+ export const generateUniqueRandomBigNumber = (
38
+ length: number,
39
+ // eslint-disable-next-line
40
+ existingValues: any[],
41
+ ) => {
42
+ let result;
43
+ while (result === undefined || existingValues.includes(result)) {
44
+ result = generateRandomBigNumber(length);
45
+ }
46
+ return result;
47
+ };
@@ -0,0 +1,6 @@
1
+ export const shortAddress = (address: string): string => {
2
+ return `${address?.substring(0, 5)}...${address?.substring(
3
+ address.length - 5,
4
+ address.length,
5
+ )}`;
6
+ };
@@ -0,0 +1,14 @@
1
+ /** @type {import("tailwindcss").Config} */
2
+ module.exports = {
3
+ content: ["./src/components/**/*.{js,ts,jsx,tsx,mdx}"],
4
+ theme: {
5
+ extend: {
6
+ colors: {
7
+ x_alert: "rgb(255, 183, 77)",
8
+ x_alert_light: "rgb(255, 226, 183)",
9
+ x_blue: "#3396FF",
10
+ },
11
+ },
12
+ },
13
+ plugins: [],
14
+ };
package/test/api.test.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import fetch from "jest-fetch-mock";
2
2
  import { chains } from "./api.mock";
3
- import { getChains } from "../src/services";
3
+ import { getChains } from "@src/services";
4
4
 
5
5
  describe("API", () => {
6
6
  beforeEach(() => {
package/tsconfig.json CHANGED
@@ -11,6 +11,15 @@
11
11
  "noUncheckedIndexedAccess": true,
12
12
  "moduleResolution": "Bundler",
13
13
  "module": "ESNext",
14
- "noEmit": true
14
+ "noEmit": true,
15
+ "jsx": "react-jsx",
16
+ "paths": {
17
+ "@src/*": [
18
+ "./src/*"
19
+ ],
20
+ "@src/global.css": [
21
+ "./src/components/global.css"
22
+ ]
23
+ }
15
24
  }
16
25
  }
@@ -0,0 +1,18 @@
1
+ import { XSwapConfig } from "@src/models";
2
+
3
+ const xSwapConfig: XSwapConfig = {
4
+ apiUrl: "https://xswap.link/api",
5
+ };
6
+
7
+ let xSwapConfigLocal = {};
8
+ try {
9
+ // eslint-disable-next-line
10
+ xSwapConfigLocal = require("./xswap.config.local").default;
11
+ } catch {
12
+ // There's no local config, nothing to override.
13
+ }
14
+
15
+ export default {
16
+ ...xSwapConfig,
17
+ ...xSwapConfigLocal,
18
+ };
package/index.ts DELETED
@@ -1,5 +0,0 @@
1
- export * from "./src/constants";
2
- export * from "./src/contracts";
3
- export * from "./src/models";
4
- export * from "./src/services";
5
- export * from "./src/utils";
@@ -1,3 +0,0 @@
1
- export type ApiOverrides = {
2
- apiUrl?: string;
3
- };
@@ -1,20 +0,0 @@
1
- import { Web3Environment } from "./Web3Environment";
2
- import { Token } from "./Token";
3
-
4
- export type Chain = {
5
- ecosystem: string;
6
- chainId: string;
7
- name: string;
8
- displayName: string;
9
- image: string;
10
- web3Environment: Web3Environment;
11
- tokenSymbol: string;
12
- ccipChainId: string;
13
- transactionExplorer: string;
14
- bridgeSupported: boolean;
15
- swapSupported: boolean;
16
- tokens: Token[];
17
- publicRpcUrls: string[];
18
- privateRpcUrls?: string[];
19
- scanApiURL?: string;
20
- };
@@ -1,9 +0,0 @@
1
- export type Prices = {
2
- blockchainId: string;
3
- updatedAt: Date;
4
- prices: TokenPrice;
5
- };
6
-
7
- export type TokenPrice = {
8
- [tokenAddress: string]: string;
9
- };