@xswap-link/sdk 0.3.5 → 0.4.1

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 (199) hide show
  1. package/.eslintrc.json +9 -5
  2. package/CHANGELOG.md +16 -0
  3. package/README.md +2 -1
  4. package/dist/index.d.mts +106 -20
  5. package/dist/index.d.ts +106 -20
  6. package/dist/index.global.js +856 -307
  7. package/dist/index.global.js.map +1 -0
  8. package/dist/index.js +105 -3564
  9. package/dist/index.js.map +1 -0
  10. package/dist/index.mjs +105 -3534
  11. package/dist/index.mjs.map +1 -0
  12. package/nodemon.json +1 -1
  13. package/package.json +16 -9
  14. package/postcss.config.js +8 -1
  15. package/src/{components → assets}/icons/ArrowDownIcon.tsx +1 -2
  16. package/src/assets/icons/ArrowDownLongIcon.tsx +12 -0
  17. package/src/{components → assets}/icons/ArrowLeftIcon.tsx +1 -5
  18. package/src/{components → assets}/icons/ArrowRightIcon.tsx +1 -5
  19. package/src/assets/icons/ArrowUpIcon.tsx +12 -0
  20. package/src/{components → assets}/icons/ArrowUpRightIcon.tsx +1 -5
  21. package/src/assets/icons/CashbacklIcon.tsx +28 -0
  22. package/src/{components → assets}/icons/CheckIcon.tsx +1 -5
  23. package/src/assets/icons/ChevronDownIcon.tsx +12 -0
  24. package/src/assets/icons/ChevronUpIcon.tsx +7 -0
  25. package/src/{components → assets}/icons/CircularProgressIcon.tsx +1 -2
  26. package/src/assets/icons/CloseIcon.tsx +15 -0
  27. package/src/{components → assets}/icons/CoinsIcon.tsx +0 -2
  28. package/src/assets/icons/CopyIcon.tsx +15 -0
  29. package/src/assets/icons/DotGreenIcon.tsx +12 -0
  30. package/src/{components → assets}/icons/DownArrorIcon.tsx +0 -2
  31. package/src/{components → assets}/icons/ErrorIcon.tsx +0 -1
  32. package/src/assets/icons/ErrorModalStatusIcon.tsx +31 -0
  33. package/src/assets/icons/HelpIcon.tsx +21 -0
  34. package/src/assets/icons/HistoryGradientBgIcon.tsx +32 -0
  35. package/src/assets/icons/HistoryIcon.tsx +12 -0
  36. package/src/{components → assets}/icons/HourGlassIcon.tsx +1 -5
  37. package/src/assets/icons/Icon.tsx +5 -0
  38. package/src/{components → assets}/icons/InfoIcon.tsx +0 -1
  39. package/src/assets/icons/LinkExternalIcon.tsx +15 -0
  40. package/src/{components → assets}/icons/PercentageIcon.tsx +0 -1
  41. package/src/assets/icons/RankIcon.tsx +28 -0
  42. package/src/assets/icons/SettingsGradientBgIcon.tsx +32 -0
  43. package/src/assets/icons/SettingsIcon.tsx +12 -0
  44. package/src/{components → assets}/icons/SignIcon.tsx +0 -2
  45. package/src/{components → assets}/icons/SuccessIcon.tsx +0 -1
  46. package/src/assets/icons/SuccessModalStatusIcon.tsx +31 -0
  47. package/src/assets/icons/ThumbUpRoundedIcon.tsx +15 -0
  48. package/src/{components → assets}/icons/TimerIcon.tsx +0 -1
  49. package/src/assets/icons/TokensIcon.tsx +16 -0
  50. package/src/assets/icons/WaitingIcon.tsx +15 -0
  51. package/src/{components → assets}/icons/XMarkIcon.tsx +1 -5
  52. package/src/assets/icons/XPowerIcon.tsx +28 -0
  53. package/src/{components → assets}/icons/index.ts +16 -0
  54. package/src/components/Alert/index.tsx +1 -1
  55. package/src/components/Button/index.tsx +57 -0
  56. package/src/components/MessageBar/SnackMessage.tsx +32 -0
  57. package/src/components/MessageBar/index.tsx +44 -0
  58. package/src/components/Modal/index.tsx +52 -0
  59. package/src/components/PoweredBy/index.tsx +12 -0
  60. package/src/components/SafeInput/index.tsx +51 -0
  61. package/src/components/Skeleton/index.tsx +5 -9
  62. package/src/components/Spinner/index.tsx +6 -8
  63. package/src/components/Swap/Header/Controls/index.tsx +57 -0
  64. package/src/components/Swap/Header/index.tsx +16 -0
  65. package/src/components/Swap/HistoryView/index.tsx +34 -0
  66. package/src/components/Swap/SettingsView/Delivery/index.tsx +42 -0
  67. package/src/components/Swap/SettingsView/Slippage/index.tsx +80 -0
  68. package/src/components/Swap/SettingsView/index.tsx +11 -0
  69. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon.tsx +13 -0
  70. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Header/index.tsx +37 -0
  71. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Steps/index.tsx +145 -0
  72. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/SwapPanel/index.tsx +61 -0
  73. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +291 -0
  74. package/src/components/Swap/SwapView/ConfirmationView/TxResult/TokenItem/index.tsx +24 -0
  75. package/src/components/Swap/SwapView/ConfirmationView/TxResult/index.tsx +84 -0
  76. package/src/components/Swap/SwapView/ConfirmationView/index.tsx +17 -0
  77. package/src/components/Swap/SwapView/FeesPanel/DeliveryInfo/index.tsx +25 -0
  78. package/src/components/Swap/SwapView/FeesPanel/Fee/index.tsx +18 -0
  79. package/src/components/Swap/SwapView/FeesPanel/Fees/index.tsx +71 -0
  80. package/src/components/Swap/SwapView/FeesPanel/index.tsx +67 -0
  81. package/src/components/Swap/SwapView/SwapButton/index.tsx +154 -0
  82. package/src/components/Swap/SwapView/SwapPanel/AmountPanel/Balance/index.tsx +23 -0
  83. package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +56 -0
  84. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +70 -0
  85. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +62 -0
  86. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +74 -0
  87. package/src/components/Swap/SwapView/SwapPanel/MaxPanel/index.tsx +35 -0
  88. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx +40 -0
  89. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +62 -0
  90. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +399 -0
  91. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +104 -0
  92. package/src/components/Swap/SwapView/SwapPanel/index.tsx +42 -0
  93. package/src/components/Swap/SwapView/index.tsx +20 -0
  94. package/src/components/Swap/index.tsx +34 -0
  95. package/src/components/TextInput/index.tsx +67 -0
  96. package/src/components/Timer/index.tsx +57 -0
  97. package/src/components/ToggleButton/index.tsx +24 -0
  98. package/src/components/{UnknownTokenLogo/UnknownTokenLogo.tsx → TokenLogo/Unknown/index.tsx} +3 -4
  99. package/src/components/TokenLogo/WithChain/index.tsx +34 -0
  100. package/src/components/TokenLogo/index.tsx +22 -0
  101. package/src/components/Tooltip/index.tsx +108 -0
  102. package/src/components/TxConfigForm/index.tsx +63 -42
  103. package/src/components/TxDataCard/TokenDetails/index.tsx +30 -0
  104. package/src/components/TxDataCard/TxDataCardUI/index.tsx +133 -0
  105. package/src/components/TxDataCard/index.tsx +30 -0
  106. package/src/components/TxStatusButton/index.tsx +64 -108
  107. package/src/components/global.css +115 -4
  108. package/src/components/index.ts +18 -1
  109. package/src/config/fonts.ts +114 -0
  110. package/src/config/global.d.ts +4 -0
  111. package/src/config/init.tsx +35 -31
  112. package/src/constants/crosschainEstimationTimes.ts +52 -0
  113. package/src/constants/index.ts +8 -0
  114. package/src/context/GlobalDataProvider.tsx +165 -0
  115. package/src/context/HistoryProvider.tsx +339 -0
  116. package/src/context/ModalProvider.tsx +47 -0
  117. package/src/context/SwapProvider.tsx +664 -0
  118. package/src/context/TransactionProvider.tsx +86 -0
  119. package/src/context/TxUIWrapper.tsx +388 -0
  120. package/src/context/index.ts +5 -0
  121. package/src/contracts/abi/CustomXSwapRouter.json +953 -0
  122. package/src/contracts/abi/StakingStableAPR.json +1438 -0
  123. package/src/contracts/abi/XSwapRouter.json +1242 -0
  124. package/src/contracts/abi/XSwapTokenFeeDistributor.json +350 -0
  125. package/src/contracts/abi/index.ts +8 -0
  126. package/src/contracts/addresses.ts +24 -6
  127. package/src/fonts/Satoshi-Black.woff2 +0 -0
  128. package/src/fonts/Satoshi-BlackItalic.woff2 +0 -0
  129. package/src/fonts/Satoshi-Bold.woff2 +0 -0
  130. package/src/fonts/Satoshi-BoldItalic.woff2 +0 -0
  131. package/src/fonts/Satoshi-Light.woff2 +0 -0
  132. package/src/fonts/Satoshi-LightItalic.woff2 +0 -0
  133. package/src/fonts/Satoshi-Medium.woff2 +0 -0
  134. package/src/fonts/Satoshi-MediumItalic.woff2 +0 -0
  135. package/src/fonts/Satoshi-Regular.woff2 +0 -0
  136. package/src/fonts/Satoshi-RegularItalic.woff2 +0 -0
  137. package/src/fonts/Satoshi-Variable.woff2 +0 -0
  138. package/src/fonts/Satoshi-VariableItalic.woff2 +0 -0
  139. package/src/hooks/index.ts +5 -0
  140. package/src/hooks/networkManagement/clientToSigner.tsx +17 -0
  141. package/src/hooks/networkManagement/useNetworks.ts +51 -0
  142. package/src/hooks/useBatchQuery.ts +46 -0
  143. package/src/hooks/useDebounce.tsx +28 -0
  144. package/src/hooks/useEvmContractApi.ts +85 -0
  145. package/src/hooks/usePortal.ts +79 -0
  146. package/src/hooks/useXPower.ts +58 -0
  147. package/src/models/Addresses.ts +8 -2
  148. package/src/models/TokenData.ts +13 -0
  149. package/src/models/TransactionHistory.ts +2 -0
  150. package/src/models/TxUIWrapper.ts +51 -0
  151. package/src/models/XSwapConfig.ts +1 -0
  152. package/src/models/index.ts +1 -0
  153. package/src/models/payloads/GetBalancesPayload.ts +3 -0
  154. package/src/models/payloads/GetFinishedLeaderboardQuestsPayload.ts +3 -0
  155. package/src/models/payloads/GetLeaderboardChangePayload.ts +4 -0
  156. package/src/models/payloads/{GetSwapTxPayload.ts → ModalIntegrationPayload.ts} +3 -1
  157. package/src/models/payloads/index.ts +5 -2
  158. package/src/services/api.ts +34 -5
  159. package/src/services/integrations/monitoring.ts +49 -37
  160. package/src/services/integrations/transactions.ts +50 -6
  161. package/src/utils/contracts.ts +29 -0
  162. package/src/utils/index.ts +3 -3
  163. package/src/utils/numbers.ts +14 -0
  164. package/src/utils/parseWeb3Error.ts +7 -3
  165. package/tailwind.config.js +15 -5
  166. package/tsconfig.json +7 -7
  167. package/tsup.config.ts +62 -0
  168. package/xswap.config.ts +1 -0
  169. package/dist/index.css +0 -1
  170. package/src/components/TxConfigForm/BalanceComponent.tsx +0 -52
  171. package/src/components/TxConfigForm/Button.tsx +0 -20
  172. package/src/components/TxConfigForm/ChainListElement.tsx +0 -36
  173. package/src/components/TxConfigForm/ConfirmationAmount.tsx +0 -91
  174. package/src/components/TxConfigForm/ConfirmationView/ErrorView.tsx +0 -38
  175. package/src/components/TxConfigForm/ConfirmationView/SuccessView.tsx +0 -159
  176. package/src/components/TxConfigForm/ConfirmationView/index.tsx +0 -149
  177. package/src/components/TxConfigForm/ConnectWalletPrompt.tsx +0 -21
  178. package/src/components/TxConfigForm/Description.tsx +0 -17
  179. package/src/components/TxConfigForm/ErrorField.tsx +0 -19
  180. package/src/components/TxConfigForm/FeesDetails.tsx +0 -117
  181. package/src/components/TxConfigForm/Form.tsx +0 -574
  182. package/src/components/TxConfigForm/History.tsx +0 -131
  183. package/src/components/TxConfigForm/HistoryCard.tsx +0 -182
  184. package/src/components/TxConfigForm/PoweredBy.tsx +0 -12
  185. package/src/components/TxConfigForm/Settings.tsx +0 -143
  186. package/src/components/TxConfigForm/Summary.tsx +0 -105
  187. package/src/components/TxConfigForm/SwapPanel.tsx +0 -185
  188. package/src/components/TxConfigForm/TokenPicker.tsx +0 -176
  189. package/src/components/TxConfigForm/TopBar.tsx +0 -58
  190. package/src/components/TxConfigForm/UsdPrice.tsx +0 -44
  191. package/src/components/icons/ChevronDownIcon.tsx +0 -15
  192. package/src/components/icons/ChevronUpIcon.tsx +0 -10
  193. package/src/components/icons/CloseIcon.tsx +0 -15
  194. package/src/components/icons/HistoryIcon.tsx +0 -16
  195. package/src/components/icons/SettingsIcon.tsx +0 -16
  196. /package/src/{components → assets}/icons/ChainlinkCCIPIcon.tsx +0 -0
  197. /package/src/{components → assets}/icons/SearchIcon.tsx +0 -0
  198. /package/src/{components → assets}/icons/XSwapBadgeIcon.tsx +0 -0
  199. /package/src/{components → assets}/icons/XSwapLogo.tsx +0 -0
@@ -0,0 +1,664 @@
1
+ import { TxConfigFormPayload } from "@src/components";
2
+ import {
3
+ DEFAULT_REQUEST_ABORT_MSG,
4
+ DEFAULT_SOURCE_CHAIN_ID,
5
+ DEFAULT_SOURCE_TOKEN_ADDR,
6
+ } from "@src/constants";
7
+ import { ADDRESSES } from "@src/contracts";
8
+ import {
9
+ Chain,
10
+ Route,
11
+ Token,
12
+ TokenOption,
13
+ TokenPrices,
14
+ Transaction,
15
+ Web3Environment,
16
+ } from "@src/models";
17
+ import { getBalances, getPrices, getRoute } from "@src/services";
18
+ import {
19
+ deepMergeObjects,
20
+ getBalanceOf,
21
+ humanReadableToWei,
22
+ safeBigNumberFrom,
23
+ weiToHumanReadable,
24
+ } from "@src/utils";
25
+ import BigNumberJS from "bignumber.js";
26
+ import { BigNumber, constants } from "ethers";
27
+ import {
28
+ createContext,
29
+ Dispatch,
30
+ ReactNode,
31
+ SetStateAction,
32
+ useCallback,
33
+ useContext,
34
+ useEffect,
35
+ useMemo,
36
+ useRef,
37
+ useState,
38
+ } from "react";
39
+ import { Config, useAccount } from "wagmi";
40
+ import { useHistory } from "./HistoryProvider";
41
+
42
+ type Tab = "Swap" | "History" | "Settings";
43
+ type SwapContext = {
44
+ integrationConfig: Partial<TxConfigFormPayload>;
45
+ wagmiConfig: Config;
46
+ supportedChains: Chain[];
47
+ tab: Tab;
48
+ setTab: Dispatch<SetStateAction<Tab>>;
49
+ error: string;
50
+ setError: Dispatch<SetStateAction<string>>;
51
+ feeToken: Token | undefined;
52
+ srcChain: Chain | undefined;
53
+ setSrcChain: Dispatch<SetStateAction<Chain | undefined>>;
54
+ srcChainTokensOptions: TokenOption[];
55
+ srcChainOtherTokensOptions: TokenOption[];
56
+ srcChainTokensPrices: TokenPrices;
57
+ dstChainTokensPrices: TokenPrices;
58
+ srcToken: Token | undefined;
59
+ setSrcToken: Dispatch<SetStateAction<Token | undefined>>;
60
+ dstChain: Chain | undefined;
61
+ setDstChain: Dispatch<SetStateAction<Chain | undefined>>;
62
+ dstChainTokensOptions: TokenOption[];
63
+ dstChainOtherTokensOptions: TokenOption[];
64
+ dstToken: Token | undefined;
65
+ setDstToken: Dispatch<SetStateAction<Token | undefined>>;
66
+ srcValue: string;
67
+ setSrcValue: Dispatch<SetStateAction<string>>;
68
+ srcValueWei: string;
69
+ srcValueUsd: string;
70
+ dstValue: string;
71
+ dstValueWei: string;
72
+ dstValueUsd: string;
73
+ dstValueMin: string;
74
+ lastTx: Transaction | undefined;
75
+ setLastTxHash: Dispatch<SetStateAction<string>>;
76
+ expressDelivery: boolean;
77
+ setExpressDelivery: Dispatch<SetStateAction<boolean>>;
78
+ slippage: string;
79
+ setSlippage: Dispatch<SetStateAction<string>>;
80
+ route: Route | undefined;
81
+ setRoute: Dispatch<SetStateAction<Route | undefined>>;
82
+ isAsyncDataLoaded: boolean;
83
+ srcTokenBalanceWei: string;
84
+ setSrcTokenBalanceWei: Dispatch<SetStateAction<string>>;
85
+ srcTokenBalanceInfo: string;
86
+ isFetchingRoute: boolean;
87
+ isFetchingBalance: boolean;
88
+ isExpressDeliveryActive: boolean;
89
+ quoteRoute: () => Promise<void>;
90
+ refreshBalance: () => void;
91
+ findTokenDataByAddressAndChain: (
92
+ tokenAddress: string,
93
+ chainId: string,
94
+ ) => Token | undefined;
95
+ };
96
+
97
+ const functionNotImplemented = () => {
98
+ throw new Error("Not implemented");
99
+ };
100
+
101
+ const init: SwapContext = {
102
+ integrationConfig: {},
103
+ wagmiConfig: {} as Config,
104
+ supportedChains: [],
105
+ tab: "Swap",
106
+ error: "",
107
+ feeToken: undefined,
108
+ srcChain: undefined,
109
+ srcChainTokensOptions: [],
110
+ srcChainOtherTokensOptions: [],
111
+ srcChainTokensPrices: {},
112
+ dstChainTokensPrices: {},
113
+ dstChain: undefined,
114
+ dstChainTokensOptions: [],
115
+ dstChainOtherTokensOptions: [],
116
+ srcToken: undefined,
117
+ dstToken: undefined,
118
+ srcValue: "",
119
+ srcValueWei: "",
120
+ srcValueUsd: "",
121
+ dstValue: "",
122
+ dstValueWei: "",
123
+ dstValueUsd: "",
124
+ dstValueMin: "",
125
+ lastTx: undefined,
126
+ expressDelivery: true,
127
+ slippage: "1.5",
128
+ route: undefined,
129
+ isAsyncDataLoaded: false,
130
+ srcTokenBalanceWei: "",
131
+ srcTokenBalanceInfo: "-",
132
+ isFetchingBalance: false,
133
+ isFetchingRoute: false,
134
+ isExpressDeliveryActive: true,
135
+ setTab: functionNotImplemented,
136
+ setError: functionNotImplemented,
137
+ setSrcChain: functionNotImplemented,
138
+ setDstChain: functionNotImplemented,
139
+ setSrcToken: functionNotImplemented,
140
+ setDstToken: functionNotImplemented,
141
+ setSrcValue: functionNotImplemented,
142
+ setLastTxHash: functionNotImplemented,
143
+ setExpressDelivery: functionNotImplemented,
144
+ setSlippage: functionNotImplemented,
145
+ setRoute: functionNotImplemented,
146
+ setSrcTokenBalanceWei: functionNotImplemented,
147
+ quoteRoute: functionNotImplemented,
148
+ refreshBalance: functionNotImplemented,
149
+ findTokenDataByAddressAndChain: functionNotImplemented,
150
+ };
151
+
152
+ const swapContext = createContext(init);
153
+
154
+ type Props = {
155
+ children: ReactNode;
156
+ integrationConfig: Partial<TxConfigFormPayload>;
157
+ supportedChains: Chain[];
158
+ wagmiConfig: Config;
159
+ };
160
+ export const SwapProvider = ({
161
+ children,
162
+ integrationConfig,
163
+ supportedChains,
164
+ wagmiConfig,
165
+ }: Props) => {
166
+ const { address } = useAccount();
167
+ const [tab, setTab] = useState(init.tab);
168
+ const [error, setError] = useState(init.error);
169
+ const [expressDelivery, setExpressDelivery] = useState(init.expressDelivery);
170
+ const [slippage, setSlippage] = useState(init.slippage);
171
+ const [srcChain, setSrcChain] = useState(init.srcChain);
172
+ const [dstChain, setDstChain] = useState(init.dstChain);
173
+ const [feeToken, setFeeToken] = useState(init.feeToken);
174
+ const [srcToken, setSrcToken] = useState(init.srcToken);
175
+ const [dstToken, setDstToken] = useState(init.dstToken);
176
+ const [srcValue, setSrcValue] = useState(init.srcValue);
177
+ const [isFetchingBalance, setIsFetchingBalance] = useState(
178
+ init.isFetchingBalance,
179
+ );
180
+ const [srcTokenBalanceWei, setSrcTokenBalanceWei] = useState(
181
+ init.srcTokenBalanceWei,
182
+ );
183
+ const [isFetchingRoute, setFetchingRoute] = useState(init.isFetchingRoute);
184
+ const [route, setRoute] = useState(init.route);
185
+
186
+ const [lastTxHash, setLastTxHash] = useState("");
187
+
188
+ const [srcChainTokensOptions, setSrcChainTokensOptions] = useState(
189
+ init.srcChainTokensOptions,
190
+ );
191
+ const [dstChainTokensOptions, setDstChainTokensOptions] = useState(
192
+ init.dstChainTokensOptions,
193
+ );
194
+ const [srcChainTokensPrices, setSrcChainTokensPrices] = useState(
195
+ init.srcChainTokensPrices,
196
+ );
197
+ const [dstChainTokensPrices, setDstChainTokensPrices] = useState(
198
+ init.dstChainTokensPrices,
199
+ );
200
+ const [srcChainOtherTokensOptions, setSrcChainOtherTokensOptions] = useState(
201
+ init.srcChainOtherTokensOptions,
202
+ );
203
+ const [dstChainOtherTokensOptions, setDstChainOtherTokensOptions] = useState(
204
+ init.dstChainOtherTokensOptions,
205
+ );
206
+
207
+ const routeAbortController = useRef<AbortController | null>(null);
208
+ const getTokenBalancesNonce = useRef(0);
209
+
210
+ const { history } = useHistory();
211
+
212
+ const supportedTokens: Record<string, Record<string, Token>> = useMemo(() => {
213
+ const customTokens = JSON.parse(
214
+ localStorage.getItem("custom-tokens") || "{}",
215
+ );
216
+ const chainIdToTokenAddressToData: {
217
+ [chainId: string]: {
218
+ [tokenAddress: string]: Token;
219
+ };
220
+ } = {};
221
+ supportedChains.forEach((chain) => {
222
+ chainIdToTokenAddressToData[chain.chainId] = {};
223
+ chain.tokens.forEach((token) => {
224
+ // @ts-expect-error TODO
225
+ chainIdToTokenAddressToData[chain.chainId][token.address] = token;
226
+ });
227
+ });
228
+ return deepMergeObjects(chainIdToTokenAddressToData, customTokens);
229
+ // eslint-disable-next-line react-hooks/exhaustive-deps
230
+ }, [supportedChains]);
231
+
232
+ const chainToTokenOptionsMap = useMemo(() => {
233
+ const tempChainToTokenOptionsMap: Record<string, TokenOption[]> = {};
234
+ Object.entries(supportedTokens).forEach(([chainId, chainData]) => {
235
+ tempChainToTokenOptionsMap[chainId] = Object.entries(chainData)
236
+ .filter(([, tokenData]) => tokenData.supported)
237
+ .sort(([, tokenDataA], [, tokenDataB]) => {
238
+ return tokenDataB.priority - tokenDataA.priority;
239
+ })
240
+ .map(([, tokenData]) => {
241
+ return {
242
+ chainId: chainId,
243
+ ...tokenData,
244
+ };
245
+ });
246
+ });
247
+ return tempChainToTokenOptionsMap;
248
+ }, [supportedTokens]);
249
+
250
+ const getTokenOptions = useCallback(
251
+ (chainId: string, oppositeChainId: string) => {
252
+ if (!chainId || !oppositeChainId) {
253
+ return [];
254
+ }
255
+ return chainToTokenOptionsMap[chainId] || [];
256
+ },
257
+ [chainToTokenOptionsMap],
258
+ );
259
+
260
+ const srcTokenBalanceInfo = useMemo(() => {
261
+ if (!srcToken || !srcTokenBalanceWei) {
262
+ return "";
263
+ }
264
+
265
+ if (safeBigNumberFrom(srcTokenBalanceWei).eq(0)) {
266
+ return "0";
267
+ }
268
+
269
+ const fullHumanReadableBalance = weiToHumanReadable({
270
+ amount: srcTokenBalanceWei,
271
+ decimals: srcToken.decimals,
272
+ precisionFractionalPlaces: srcToken.decimals,
273
+ });
274
+
275
+ if (new BigNumberJS(fullHumanReadableBalance).lt("0.00001")) {
276
+ return "<0.00001";
277
+ }
278
+
279
+ // Shortened to cut non-significant decimals
280
+ return weiToHumanReadable({
281
+ amount: srcTokenBalanceWei,
282
+ decimals: srcToken.decimals,
283
+ precisionFractionalPlaces: 5,
284
+ });
285
+ }, [srcToken, srcTokenBalanceWei]);
286
+
287
+ const lastTx = useMemo(() => {
288
+ return history?.find(({ hash }) => hash === lastTxHash);
289
+ }, [history, lastTxHash]);
290
+
291
+ const srcValueWei = useMemo(
292
+ () =>
293
+ humanReadableToWei({
294
+ amount: srcValue,
295
+ decimals: srcToken?.decimals || 18,
296
+ }),
297
+ [srcToken?.decimals, srcValue],
298
+ );
299
+
300
+ // fetch srcTokenPrices
301
+ useEffect(() => {
302
+ if (srcChain) {
303
+ getPrices({ chainId: srcChain.chainId, currency: "USD" }).then((prices) =>
304
+ setSrcChainTokensPrices(prices),
305
+ );
306
+ }
307
+ }, [srcChain]);
308
+
309
+ // fetch dstTokenPrices
310
+ useEffect(() => {
311
+ if (dstChain) {
312
+ getPrices({ chainId: dstChain.chainId, currency: "USD" }).then((prices) =>
313
+ setDstChainTokensPrices(prices),
314
+ );
315
+ }
316
+ }, [dstChain]);
317
+
318
+ const srcValueUsd = useMemo(() => {
319
+ if (
320
+ srcToken &&
321
+ srcChainTokensPrices &&
322
+ srcChainTokensPrices[srcToken.address]
323
+ ) {
324
+ return (
325
+ Number(srcValue) * Number(srcChainTokensPrices[srcToken.address])
326
+ ).toFixed(2);
327
+ }
328
+ return "0";
329
+ }, [srcChainTokensPrices, srcToken, srcValue]);
330
+ const dstValue = useMemo(
331
+ () =>
332
+ weiToHumanReadable({
333
+ amount: route?.estAmountOut || "0", // TODO include fees.xSwapFee.tokenFee
334
+ decimals: dstToken?.decimals || 18,
335
+ precisionFractionalPlaces: Math.min(8, dstToken?.decimals || 18),
336
+ }),
337
+ // eslint-disable-next-line react-hooks/exhaustive-deps
338
+ [route],
339
+ );
340
+ const dstValueWei = useMemo(
341
+ () =>
342
+ humanReadableToWei({
343
+ amount: dstValue,
344
+ decimals: dstToken?.decimals || 18,
345
+ }),
346
+ [dstToken?.decimals, dstValue],
347
+ );
348
+ const dstValueUsd = useMemo(() => {
349
+ if (
350
+ dstToken &&
351
+ dstChainTokensPrices &&
352
+ dstChainTokensPrices[dstToken.address]
353
+ ) {
354
+ return (
355
+ Number(dstValue) * Number(dstChainTokensPrices[dstToken.address])
356
+ ).toFixed(2);
357
+ }
358
+ return "0";
359
+ }, [dstChainTokensPrices, dstToken, dstValue]);
360
+ const dstValueMin = useMemo(
361
+ () =>
362
+ weiToHumanReadable({
363
+ amount: route?.minAmountOut || "0",
364
+ decimals: dstToken?.decimals || 18,
365
+ precisionFractionalPlaces: Math.min(4, dstToken?.decimals || 18),
366
+ }),
367
+ // eslint-disable-next-line react-hooks/exhaustive-deps
368
+ [route],
369
+ );
370
+
371
+ const isExpressDeliveryActive = useMemo(
372
+ () =>
373
+ expressDelivery &&
374
+ !!route &&
375
+ BigNumber.from(route.xSwapFees?.expressDeliveryFee || "0").gt("0"),
376
+ [expressDelivery, route],
377
+ );
378
+
379
+ const isAsyncDataLoaded = useMemo(
380
+ () => supportedChains.length > 0,
381
+ [supportedChains],
382
+ );
383
+
384
+ const quoteRoute = useCallback(async () => {
385
+ if (
386
+ !srcChain ||
387
+ !dstChain ||
388
+ !srcToken ||
389
+ !dstToken ||
390
+ !srcValueWei ||
391
+ safeBigNumberFrom(srcValueWei).eq(0)
392
+ ) {
393
+ setRoute(undefined);
394
+ return;
395
+ }
396
+ try {
397
+ setError("");
398
+ setFetchingRoute(true);
399
+
400
+ if (routeAbortController.current) {
401
+ routeAbortController.current.abort(DEFAULT_REQUEST_ABORT_MSG);
402
+ }
403
+ routeAbortController.current = new AbortController();
404
+ const route = await getRoute(
405
+ {
406
+ integratorId: integrationConfig.integratorId!,
407
+ fromChain: srcChain.chainId,
408
+ toChain: dstChain.chainId,
409
+ fromAddress:
410
+ address || ADDRESSES[srcChain.chainId]?.FeeCollector || "",
411
+ toAddress: address || ADDRESSES[dstChain.chainId]?.FeeCollector || "",
412
+ fromToken: srcToken.address,
413
+ toToken: dstToken.address,
414
+ fromAmount: srcValueWei,
415
+ slippage: Number(slippage),
416
+ customContractCalls: integrationConfig.customContractCalls,
417
+ paymentToken: constants.AddressZero,
418
+ expressDelivery: expressDelivery,
419
+ },
420
+ routeAbortController.current.signal,
421
+ );
422
+
423
+ setRoute(route);
424
+ setFetchingRoute(false);
425
+ routeAbortController.current = null;
426
+ } catch (error) {
427
+ if (error !== DEFAULT_REQUEST_ABORT_MSG) {
428
+ console.error(error);
429
+ setError("Could not find route!");
430
+ setRoute(undefined);
431
+ }
432
+ }
433
+ // eslint-disable-next-line react-hooks/exhaustive-deps
434
+ }, [
435
+ address,
436
+ dstChain,
437
+ dstToken,
438
+ getRoute,
439
+ isExpressDeliveryActive,
440
+ slippage,
441
+ srcChain,
442
+ srcToken,
443
+ srcValueWei,
444
+ ]);
445
+
446
+ useEffect(() => {
447
+ quoteRoute();
448
+ }, [quoteRoute]);
449
+
450
+ useEffect(() => {
451
+ if (!srcChain || !dstChain) {
452
+ return;
453
+ }
454
+ (async () => {
455
+ // source chain
456
+ const srcTokenOptions: TokenOption[] = getTokenOptions(
457
+ srcChain.chainId,
458
+ dstChain.chainId,
459
+ ).filter(({ symbol }) =>
460
+ dstChain.chainId === srcChain.chainId
461
+ ? symbol !== dstToken?.symbol
462
+ : true,
463
+ );
464
+ setSrcChainTokensOptions(srcTokenOptions);
465
+
466
+ // destination chain
467
+ const dstTokenOptions: TokenOption[] = getTokenOptions(
468
+ dstChain.chainId,
469
+ srcChain.chainId,
470
+ ).filter(({ symbol }) =>
471
+ dstChain.chainId === srcChain.chainId
472
+ ? symbol !== srcToken?.symbol
473
+ : true,
474
+ );
475
+ setDstChainTokensOptions(dstTokenOptions);
476
+
477
+ // other source networks
478
+ const srcOtherTokenOptions: TokenOption[] = [];
479
+ const srcOtherChains = supportedChains.filter(
480
+ ({ chainId, web3Environment, swapSupported }) =>
481
+ chainId !== srcChain.chainId &&
482
+ web3Environment === Web3Environment.MAINNET &&
483
+ swapSupported,
484
+ );
485
+ for (const { chainId } of srcOtherChains) {
486
+ srcOtherTokenOptions.push(
487
+ ...getTokenOptions(chainId, dstChain.chainId).filter(({ symbol }) =>
488
+ chainId === dstChain.chainId ? symbol !== dstToken?.symbol : true,
489
+ ),
490
+ );
491
+ }
492
+ setSrcChainOtherTokensOptions(srcOtherTokenOptions);
493
+
494
+ // other destination networks
495
+ const dstOtherTokenOptions: TokenOption[] = [];
496
+ const dstOtherChains = supportedChains.filter(
497
+ ({ chainId, web3Environment, swapSupported }) =>
498
+ chainId !== dstChain.chainId &&
499
+ web3Environment === Web3Environment.MAINNET &&
500
+ swapSupported,
501
+ );
502
+ for (const { chainId } of dstOtherChains) {
503
+ dstOtherTokenOptions.push(
504
+ ...getTokenOptions(chainId, srcChain.chainId).filter(({ symbol }) =>
505
+ chainId === srcChain.chainId ? symbol !== srcToken?.symbol : true,
506
+ ),
507
+ );
508
+ }
509
+ setDstChainOtherTokensOptions(dstOtherTokenOptions);
510
+
511
+ if (address) {
512
+ const nonce = Date.now();
513
+
514
+ getTokenBalancesNonce.current = nonce;
515
+
516
+ const tokenBalancesResponse = await getBalances({
517
+ walletAddress: address,
518
+ });
519
+
520
+ const addBalances = (tokenOptions: TokenOption[]) => {
521
+ return tokenOptions.map((token) => ({
522
+ ...token,
523
+ balance: BigNumber.from(
524
+ tokenBalancesResponse[token.chainId][token.address] || 0,
525
+ ),
526
+ }));
527
+ };
528
+
529
+ if (getTokenBalancesNonce.current === nonce) {
530
+ setSrcChainTokensOptions(addBalances(srcTokenOptions));
531
+ setDstChainTokensOptions(addBalances(dstTokenOptions));
532
+ setSrcChainOtherTokensOptions(addBalances(srcOtherTokenOptions));
533
+ setDstChainOtherTokensOptions(addBalances(dstOtherTokenOptions));
534
+ }
535
+ }
536
+ })();
537
+ }, [
538
+ srcChain,
539
+ dstChain,
540
+ address,
541
+ getTokenOptions,
542
+ supportedChains,
543
+ srcToken?.symbol,
544
+ dstToken?.symbol,
545
+ ]);
546
+
547
+ const refreshBalance = useCallback(() => {
548
+ if (address && srcChain?.publicRpcUrls[0] && srcToken) {
549
+ setIsFetchingBalance(true);
550
+ getBalanceOf(address, srcToken.address, srcChain?.publicRpcUrls[0]).then(
551
+ (balance) => {
552
+ setSrcTokenBalanceWei(
553
+ humanReadableToWei({
554
+ amount: balance,
555
+ decimals: srcToken.decimals,
556
+ }),
557
+ );
558
+ setIsFetchingBalance(false);
559
+ },
560
+ );
561
+ }
562
+ }, [address, srcChain, srcToken]);
563
+
564
+ const findTokenDataByAddressAndChain = useCallback(
565
+ (tokenAddress: string, chainId: string): Token | undefined => {
566
+ return supportedTokens[chainId]?.[tokenAddress];
567
+ },
568
+ [supportedTokens],
569
+ );
570
+
571
+ useEffect(() => {
572
+ refreshBalance();
573
+ }, [refreshBalance]);
574
+
575
+ useEffect(() => {
576
+ setFeeToken(
577
+ srcChain?.tokens.find(({ address }) => address === constants.AddressZero),
578
+ );
579
+ }, [srcChain]);
580
+
581
+ useEffect(() => {
582
+ const initSrcChain = supportedChains.find(
583
+ ({ chainId }) =>
584
+ chainId === (integrationConfig?.srcChainId || DEFAULT_SOURCE_CHAIN_ID),
585
+ );
586
+ const initSrcToken = initSrcChain?.tokens.find(
587
+ ({ address }) =>
588
+ address ===
589
+ (integrationConfig?.srcTokenAddr || DEFAULT_SOURCE_TOKEN_ADDR),
590
+ );
591
+ const initDstChain = supportedChains.find(
592
+ ({ chainId }) => chainId === integrationConfig.dstChainId,
593
+ );
594
+ const initDstToken = initDstChain?.tokens.find(
595
+ ({ address }) => address === integrationConfig.dstTokenAddr,
596
+ );
597
+
598
+ setSrcChain(initSrcChain);
599
+ setSrcToken(initSrcToken);
600
+ setDstChain(initDstChain);
601
+ setDstToken(initDstToken);
602
+ }, [integrationConfig, supportedChains]);
603
+
604
+ return (
605
+ <swapContext.Provider
606
+ value={{
607
+ integrationConfig,
608
+ wagmiConfig,
609
+ supportedChains,
610
+ tab,
611
+ setTab,
612
+ error,
613
+ setError,
614
+ feeToken,
615
+ srcChain,
616
+ setSrcChain,
617
+ srcChainTokensOptions,
618
+ srcChainOtherTokensOptions,
619
+ dstChainTokensPrices,
620
+ srcChainTokensPrices,
621
+ dstChain,
622
+ setDstChain,
623
+ dstChainTokensOptions,
624
+ dstChainOtherTokensOptions,
625
+ srcToken,
626
+ setSrcToken,
627
+ dstToken,
628
+ setDstToken,
629
+ srcValue,
630
+ setSrcValue,
631
+ srcValueWei,
632
+ srcValueUsd,
633
+ dstValue,
634
+ dstValueWei,
635
+ dstValueUsd,
636
+ dstValueMin,
637
+ lastTx,
638
+ setLastTxHash,
639
+ expressDelivery,
640
+ setExpressDelivery,
641
+ slippage,
642
+ setSlippage,
643
+ route,
644
+ setRoute,
645
+ isAsyncDataLoaded,
646
+ srcTokenBalanceWei,
647
+ setSrcTokenBalanceWei,
648
+ srcTokenBalanceInfo,
649
+ isFetchingRoute,
650
+ isFetchingBalance,
651
+ isExpressDeliveryActive,
652
+ quoteRoute,
653
+ refreshBalance,
654
+ findTokenDataByAddressAndChain,
655
+ }}
656
+ >
657
+ {children}
658
+ </swapContext.Provider>
659
+ );
660
+ };
661
+
662
+ export const useSwapContext = () => {
663
+ return useContext(swapContext);
664
+ };