@xswap-link/sdk 0.7.0 → 0.8.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 (37) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/index.d.mts +122 -70
  3. package/dist/index.d.ts +122 -70
  4. package/dist/index.global.js +686 -281
  5. package/dist/index.js +10 -10
  6. package/dist/index.mjs +10 -10
  7. package/package.json +1 -1
  8. package/src/assets/icons/ArrowsExchange.tsx +18 -0
  9. package/src/assets/icons/index.ts +1 -0
  10. package/src/components/Swap/Header/index.tsx +4 -2
  11. package/src/components/Swap/HistoryView/index.tsx +2 -2
  12. package/src/components/Swap/ReorderButton/ReorderButton.tsx +37 -0
  13. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon.tsx +1 -1
  14. package/src/components/Swap/SwapView/SwapButton/index.tsx +3 -1
  15. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +55 -22
  16. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +71 -6
  17. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +68 -15
  18. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +10 -2
  19. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +31 -11
  20. package/src/components/Swap/SwapView/SwapPanel/index.tsx +8 -3
  21. package/src/components/Swap/SwapView/index.tsx +3 -3
  22. package/src/components/Swap/index.tsx +1 -1
  23. package/src/components/TxConfigForm/index.tsx +57 -4
  24. package/src/components/TxWidgetWC/index.tsx +47 -2
  25. package/src/components/TxWidgetWCWrapped/index.tsx +33 -1
  26. package/src/config/index.ts +1 -1
  27. package/src/context/SwapProvider.tsx +177 -27
  28. package/src/models/BridgeTokensDictionary.ts +7 -0
  29. package/src/models/TokenData.ts +3 -1
  30. package/src/models/index.ts +6 -5
  31. package/src/models/payloads/ModalIntegrationPayload.ts +15 -1
  32. package/src/models/payloads/WidgetIntegrationPayload.ts +15 -1
  33. package/src/services/api.ts +6 -1
  34. package/src/services/integrations/transactions.ts +20 -0
  35. package/src/types/global.d.ts +15 -0
  36. package/src/utils/validation.ts +383 -0
  37. package/tsconfig.json +3 -2
@@ -1,7 +1,6 @@
1
1
  export * from "./Addresses";
2
- export * from "./XSwapConfig";
3
2
  export * from "./BridgeToken";
4
- export * from "./TokenData";
3
+ export * from "./BridgeTokensDictionary";
5
4
  export * from "./CoinTypeAddress";
6
5
  export * from "./CollectFees";
7
6
  export * from "./ContractCall";
@@ -11,9 +10,11 @@ export * from "./forms";
11
10
  export * from "./integrations";
12
11
  export * from "./payloads";
13
12
  export * from "./Protocol";
14
- export * from "./Route";
15
- export * from "./Web3Environment";
16
- export * from "./XSwapCallType";
17
13
  export * from "./Referral";
14
+ export * from "./Route";
15
+ export * from "./TokenData";
18
16
  export * from "./TransactionHistory";
19
17
  export * from "./TxUIWrapper";
18
+ export * from "./Web3Environment";
19
+ export * from "./XSwapCallType";
20
+ export * from "./XSwapConfig";
@@ -1,4 +1,4 @@
1
- import { ContractCall } from "@src/models";
1
+ import { ContractCall, Transaction } from "@src/models";
2
2
 
3
3
  export type ModalIntegrationThemeStyles = {
4
4
  mainAccentLight?: string;
@@ -48,4 +48,18 @@ export type ModalIntegrationPayload = {
48
48
  lightTheme?: boolean;
49
49
  defaultWalletPicker?: boolean;
50
50
  styles?: ModalIntegrationStyles;
51
+ onPendingTransactionsChange?: (transactions: Transaction[]) => void;
52
+ dstTokenLocked?: boolean;
53
+ dstChainLocked?: boolean;
54
+ srcTokenLocked?: boolean;
55
+ srcChainLocked?: boolean;
56
+ onDstTokenChange?: (
57
+ token: { address: string; symbol: string } | undefined,
58
+ ) => void;
59
+ onDstChainChange?: (chain: string | undefined) => void;
60
+ onSrcTokenChange?: (
61
+ token: { address: string; symbol: string } | undefined,
62
+ ) => void;
63
+ onSrcChainChange?: (chain: string | undefined) => void;
64
+ bridge?: boolean;
51
65
  };
@@ -1,4 +1,4 @@
1
- import { ContractCall, ModalIntegrationStyles } from "@src/models";
1
+ import { ContractCall, ModalIntegrationStyles, Transaction } from "@src/models";
2
2
 
3
3
  export type WidgetIntegrationPayload = {
4
4
  integratorId: string;
@@ -12,4 +12,18 @@ export type WidgetIntegrationPayload = {
12
12
  lightTheme?: boolean;
13
13
  defaultWalletPicker?: boolean;
14
14
  styles?: ModalIntegrationStyles | string;
15
+ onPendingTransactionsChange?: (transactions: Transaction[]) => void;
16
+ dstTokenLocked?: boolean;
17
+ dstChainLocked?: boolean;
18
+ srcTokenLocked?: boolean;
19
+ srcChainLocked?: boolean;
20
+ onDstTokenChange?: (
21
+ token: { address: string; symbol: string } | undefined,
22
+ ) => void;
23
+ onDstChainChange?: (chain: string | undefined) => void;
24
+ onSrcTokenChange?: (
25
+ token: { address: string; symbol: string } | undefined,
26
+ ) => void;
27
+ onSrcChainChange?: (chain: string | undefined) => void;
28
+ bridge?: boolean;
15
29
  };
@@ -1,5 +1,5 @@
1
- import xSwapConfig from "../../xswap.config";
2
1
  import {
2
+ BridgeToken,
3
3
  Chain,
4
4
  Ecosystem,
5
5
  GetFinishedLeaderboardQuestsPayload,
@@ -13,6 +13,7 @@ import {
13
13
  TransactionHistory,
14
14
  TransactionStatus,
15
15
  } from "@src/models";
16
+ import xSwapConfig from "../../xswap.config";
16
17
 
17
18
  async function _sendRequest<T>(
18
19
  urlPath: string,
@@ -153,3 +154,7 @@ export async function getFinishedLeaderboardQuests(
153
154
  })}`,
154
155
  );
155
156
  }
157
+
158
+ export async function getBridgeTokens(): Promise<BridgeToken[]> {
159
+ return _sendRequest<BridgeToken[]>(`/bridgeTokens`);
160
+ }
@@ -15,6 +15,16 @@ export const openTransactionModal = async ({
15
15
  lightTheme,
16
16
  defaultWalletPicker,
17
17
  styles,
18
+ onPendingTransactionsChange,
19
+ dstTokenLocked,
20
+ dstChainLocked,
21
+ srcTokenLocked,
22
+ srcChainLocked,
23
+ onDstTokenChange,
24
+ onDstChainChange,
25
+ onSrcTokenChange,
26
+ onSrcChainChange,
27
+ bridge,
18
28
  }: ModalIntegrationPayload) => {
19
29
  const supportedChains: Chain[] = (await getChains()).filter(
20
30
  ({ web3Environment, swapSupported }) =>
@@ -43,6 +53,16 @@ export const openTransactionModal = async ({
43
53
  lightTheme,
44
54
  defaultWalletPicker,
45
55
  styles,
56
+ onPendingTransactionsChange,
57
+ dstTokenLocked,
58
+ dstChainLocked,
59
+ srcTokenLocked,
60
+ srcChainLocked,
61
+ onDstTokenChange,
62
+ onDstChainChange,
63
+ onSrcTokenChange,
64
+ onSrcChainChange,
65
+ bridge,
46
66
  });
47
67
  };
48
68
 
@@ -0,0 +1,15 @@
1
+ import { Transaction } from "@src/models";
2
+
3
+ declare global {
4
+ interface Window {
5
+ xPayOnPendingTransactionsChange?: (transactions: Transaction[]) => void;
6
+ xPayOnDstTokenChange?: (
7
+ token: { address: string; symbol: string } | undefined,
8
+ ) => void;
9
+ xPayOnDstChainChange?: (chain: string | undefined) => void;
10
+ xPayOnSrcTokenChange?: (
11
+ token: { address: string; symbol: string } | undefined,
12
+ ) => void;
13
+ xPayOnSrcChainChange?: (chain: string | undefined) => void;
14
+ }
15
+ }
@@ -0,0 +1,383 @@
1
+ import {
2
+ DEFAULT_DESTINATION_CHAIN_ID,
3
+ DEFAULT_SOURCE_CHAIN_ID,
4
+ } from "@src/constants";
5
+ import { BridgeTokensDictionary, Chain, Token } from "@src/models";
6
+
7
+ const getDefaultSourceChain = ({
8
+ supportedChains,
9
+ }: {
10
+ supportedChains: Chain[];
11
+ }): Chain => {
12
+ const defaultSourceChain =
13
+ supportedChains.find(
14
+ (chain) => chain.chainId === DEFAULT_SOURCE_CHAIN_ID,
15
+ ) || supportedChains[0];
16
+
17
+ if (!defaultSourceChain) {
18
+ throw new Error(
19
+ `getDefaultSourceChain > couldn't find default source chain`,
20
+ );
21
+ }
22
+
23
+ return defaultSourceChain;
24
+ };
25
+
26
+ const getDefaultDestinationChain = ({
27
+ supportedChains,
28
+ }: {
29
+ supportedChains: Chain[];
30
+ }): Chain => {
31
+ const defaultTargetChain =
32
+ supportedChains.find(
33
+ (chain) => chain.chainId === DEFAULT_DESTINATION_CHAIN_ID,
34
+ ) || supportedChains[0];
35
+
36
+ if (!defaultTargetChain) {
37
+ throw new Error(
38
+ `getDefaultDestinationChain > couldn't find default destination chain`,
39
+ );
40
+ }
41
+
42
+ return defaultTargetChain;
43
+ };
44
+
45
+ const getDefaultSwapTokenForChain = (
46
+ chain: Chain,
47
+ sameChain?: boolean,
48
+ sourceTokenId?: string,
49
+ ) => {
50
+ const xswapToken = chain.tokens.find((token) => token.tokenId === "XSWAP");
51
+
52
+ if (xswapToken) {
53
+ return xswapToken;
54
+ }
55
+
56
+ const fallbackToken = chain.tokens.find((token) =>
57
+ sameChain
58
+ ? token.supported && token.tokenId !== sourceTokenId
59
+ : token.supported,
60
+ );
61
+
62
+ if (fallbackToken) {
63
+ return fallbackToken;
64
+ }
65
+
66
+ return chain.tokens[0];
67
+ };
68
+
69
+ const getDefaultBridgeTokenForChain = ({
70
+ chain,
71
+ bridgeTokensDictionary,
72
+ }: {
73
+ chain: Chain;
74
+ bridgeTokensDictionary: BridgeTokensDictionary;
75
+ }) => {
76
+ const xswapToken = chain.tokens.find((token) => token.tokenId === "XSWAP");
77
+
78
+ if (xswapToken) {
79
+ return xswapToken;
80
+ }
81
+
82
+ const fallbackTokenAddress = Object.keys(
83
+ bridgeTokensDictionary[chain.chainId] || {},
84
+ )[0];
85
+
86
+ return chain.tokens.find(
87
+ (token) =>
88
+ token.address.toLowerCase() === fallbackTokenAddress?.toLowerCase(),
89
+ );
90
+ };
91
+
92
+ const isSwapSourceValid = (sourceChain: Chain) => sourceChain.swapSupported;
93
+
94
+ const isSwapTargetChainValid = ({
95
+ sourceChain,
96
+ targetChain,
97
+ }: {
98
+ sourceChain: Chain | undefined;
99
+ targetChain: Chain;
100
+ }) => {
101
+ if (!sourceChain) {
102
+ throw new Error(`isSwapTargetChainValid > sourceChain should be defined.`);
103
+ }
104
+
105
+ return (
106
+ targetChain.swapSupported &&
107
+ !sourceChain.disabledForDestination?.includes(targetChain.chainId)
108
+ );
109
+ };
110
+
111
+ const isBridgeSourceValid = (sourceChain: Chain) => sourceChain.bridgeSupported;
112
+
113
+ const isBridgeTargetValid = ({
114
+ sourceChain,
115
+ targetChain,
116
+ sourceToken,
117
+ }: {
118
+ sourceChain: Chain | undefined;
119
+ targetChain: Chain;
120
+ sourceToken: Token | undefined;
121
+ }) => {
122
+ if (!sourceChain) {
123
+ throw new Error(`isBridgeTargetValid > sourceChain should be defined.`);
124
+ }
125
+
126
+ if (
127
+ sourceToken &&
128
+ !targetChain.tokens.find((token) => token.tokenId === sourceToken!.tokenId)
129
+ ) {
130
+ // Bridge target chain is invalid when it doesn't have the same token available as selected in the source.
131
+ return false;
132
+ }
133
+
134
+ return (
135
+ targetChain.bridgeSupported &&
136
+ // Source and target chains must be different for bridging.
137
+ sourceChain.chainId !== targetChain.chainId
138
+ );
139
+ };
140
+
141
+ // It takes chain and token for source and target and returns them.
142
+ // If provided data is valid, it returns the same.
143
+ // If data is not valid, it returns other available chain/token.
144
+ export const mapToValidPath = ({
145
+ source,
146
+ target,
147
+ type,
148
+ supportedChains,
149
+ bridgeTokensDictionary,
150
+ }: {
151
+ source: { chain: Chain | undefined; token: Token | undefined };
152
+ target: { chain: Chain | undefined; token: Token | undefined };
153
+ type: "SWAP" | "BRIDGE";
154
+ supportedChains: Chain[];
155
+ bridgeTokensDictionary: BridgeTokensDictionary;
156
+ }): {
157
+ source: { chain: Chain | undefined; token: Token | undefined };
158
+ target: { chain: Chain | undefined; token: Token | undefined };
159
+ } => {
160
+ let newSourceChain: Chain | undefined =
161
+ source.chain || getDefaultSourceChain({ supportedChains });
162
+ let newTargetChain: Chain | undefined =
163
+ target.chain || getDefaultDestinationChain({ supportedChains });
164
+ let newSourceToken: Token | undefined =
165
+ source.token ||
166
+ (type === "SWAP"
167
+ ? getDefaultSwapTokenForChain(newSourceChain)
168
+ : getDefaultBridgeTokenForChain({
169
+ chain: newSourceChain,
170
+ bridgeTokensDictionary,
171
+ }));
172
+ let newTargetToken: Token | undefined =
173
+ target.token ||
174
+ (type === "SWAP"
175
+ ? getDefaultSwapTokenForChain(
176
+ newTargetChain,
177
+ newSourceChain.chainId === newTargetChain.chainId,
178
+ newSourceToken?.tokenId,
179
+ )
180
+ : getDefaultBridgeTokenForChain({
181
+ chain: newTargetChain,
182
+ bridgeTokensDictionary,
183
+ }));
184
+
185
+ if (
186
+ !newSourceChain ||
187
+ !newTargetChain ||
188
+ !newSourceToken ||
189
+ !newTargetToken
190
+ ) {
191
+ // This should never occur if our app is configured properly.
192
+ return {
193
+ source: { chain: undefined, token: undefined },
194
+ target: { chain: undefined, token: undefined },
195
+ };
196
+ }
197
+
198
+ // Setting chains
199
+ if (type === "SWAP") {
200
+ if (!isSwapSourceValid(newSourceChain)) {
201
+ newSourceChain = getDefaultSourceChain({ supportedChains });
202
+ // We can't have dangling token from a different chain.
203
+ newSourceToken = undefined;
204
+
205
+ if (!isSwapSourceValid(newSourceChain)) {
206
+ // This should never occur if our app is configured properly.
207
+ console.error("[WRONG CONFIG] default swap source chain is invalid.");
208
+
209
+ // Find any chain that is valid.
210
+ newSourceChain = supportedChains.find((chain) =>
211
+ isSwapSourceValid(chain),
212
+ );
213
+ if (!newSourceChain) {
214
+ throw new Error(
215
+ "mapToValidSwap > None of the chains supports swap. Couldn't set source chain.",
216
+ );
217
+ }
218
+ }
219
+ }
220
+
221
+ if (
222
+ !isSwapTargetChainValid({
223
+ sourceChain: newSourceChain,
224
+ targetChain: newTargetChain,
225
+ })
226
+ ) {
227
+ newTargetChain = getDefaultDestinationChain({ supportedChains });
228
+ // We can't have dangling token from a different chain.
229
+ newTargetToken = undefined;
230
+
231
+ if (
232
+ !isSwapTargetChainValid({
233
+ sourceChain: newSourceChain,
234
+ targetChain: newTargetChain,
235
+ })
236
+ ) {
237
+ // This should never occur if our app is configured properly.
238
+ console.error("[WRONG CONFIG] default swap target chain is invalid.");
239
+
240
+ // Find any chain that is valid.
241
+ newTargetChain = supportedChains.find((chain) =>
242
+ isSwapTargetChainValid({
243
+ sourceChain: newSourceChain,
244
+ targetChain: chain,
245
+ }),
246
+ );
247
+ if (!newTargetChain) {
248
+ throw new Error(
249
+ "mapToValidSwap > None of the chains supports swap. Couldn't set target chain.",
250
+ );
251
+ }
252
+ }
253
+ }
254
+ } else {
255
+ if (!isBridgeSourceValid(newSourceChain)) {
256
+ newSourceChain = getDefaultSourceChain({ supportedChains });
257
+ // We can't have dangling token from a different chain.
258
+ newSourceToken = undefined;
259
+
260
+ if (!isBridgeSourceValid(newSourceChain)) {
261
+ // This should never occur if our app is configured properly.
262
+ console.error("[WRONG CONFIG] default bridge source chain is invalid.");
263
+
264
+ // Find any chain that is valid.
265
+ newSourceChain = supportedChains.find((chain) =>
266
+ isBridgeSourceValid(chain),
267
+ );
268
+ if (!newSourceChain) {
269
+ throw new Error(
270
+ "mapToValidSwap > None of the chains supports bridge. Couldn't set source chain.",
271
+ );
272
+ }
273
+ }
274
+ }
275
+
276
+ if (
277
+ !isBridgeTargetValid({
278
+ sourceChain: newSourceChain,
279
+ targetChain: newTargetChain,
280
+ sourceToken: newSourceToken,
281
+ })
282
+ ) {
283
+ newTargetChain = getDefaultDestinationChain({ supportedChains });
284
+ // We can't have dangling token from a different chain.
285
+ newTargetToken = undefined;
286
+
287
+ if (
288
+ !isBridgeTargetValid({
289
+ sourceChain: newSourceChain,
290
+ targetChain: newTargetChain,
291
+ sourceToken: newSourceToken,
292
+ })
293
+ ) {
294
+ // This should never occur if our app is configured properly.
295
+ console.error("[WRONG CONFIG] default bridge target chain is invalid.");
296
+
297
+ // Find any chain that is valid.
298
+ newTargetChain = supportedChains.find((chain) =>
299
+ isBridgeTargetValid({
300
+ sourceChain: newSourceChain,
301
+ targetChain: chain,
302
+ sourceToken: newSourceToken,
303
+ }),
304
+ );
305
+ if (!newTargetChain) {
306
+ throw new Error(
307
+ "mapToValidSwap > None of the chains supports swap. Couldn't set target chain.",
308
+ );
309
+ }
310
+ }
311
+ }
312
+ }
313
+
314
+ // Setting tokens
315
+ if (type === "SWAP") {
316
+ if (!newSourceToken) {
317
+ newSourceToken = getDefaultSwapTokenForChain(newSourceChain);
318
+ }
319
+ if (!newTargetToken) {
320
+ newTargetToken = getDefaultSwapTokenForChain(
321
+ newTargetChain,
322
+ newSourceChain.chainId === newTargetChain.chainId,
323
+ newSourceToken?.tokenId,
324
+ );
325
+ }
326
+ } else {
327
+ if (!newSourceToken) {
328
+ const defaultToken = getDefaultBridgeTokenForChain({
329
+ chain: newSourceChain,
330
+ bridgeTokensDictionary,
331
+ });
332
+
333
+ if (defaultToken) {
334
+ const isDefaultTokenBridgeable =
335
+ !!bridgeTokensDictionary[newSourceChain.chainId]?.[
336
+ defaultToken.address.toLowerCase()
337
+ ]?.[newTargetChain.chainId];
338
+
339
+ if (isDefaultTokenBridgeable) {
340
+ newSourceToken = defaultToken;
341
+ } else {
342
+ // This should never occur if our app is configured properly.
343
+ console.error(
344
+ "[WRONG CONFIG] default bridge source token is invalid.",
345
+ );
346
+ // Default is invalid, so let's keep it unset.
347
+ newSourceToken = undefined;
348
+ }
349
+ } else {
350
+ // Default was not found, so let's keep it unset.
351
+ newSourceToken = undefined;
352
+ }
353
+ }
354
+
355
+ if (newSourceToken?.tokenId !== newTargetToken?.tokenId) {
356
+ newTargetToken = undefined;
357
+ }
358
+
359
+ if (!newTargetToken) {
360
+ if (newSourceToken) {
361
+ const correspondingTokenAddress =
362
+ bridgeTokensDictionary[newSourceChain.chainId]?.[
363
+ newSourceToken.address.toLowerCase()
364
+ ]?.[newTargetChain.chainId];
365
+
366
+ const correspondingToken = newTargetChain.tokens.find(
367
+ (token) =>
368
+ token.address.toLowerCase() ===
369
+ correspondingTokenAddress?.toLowerCase(),
370
+ );
371
+ newTargetToken = correspondingToken;
372
+ } else {
373
+ // If source token is not defined, destination token can't be defined as well.
374
+ newTargetToken = undefined;
375
+ }
376
+ }
377
+ }
378
+
379
+ return {
380
+ source: { chain: newSourceChain, token: newSourceToken },
381
+ target: { chain: newTargetChain, token: newTargetToken },
382
+ };
383
+ };
package/tsconfig.json CHANGED
@@ -15,7 +15,8 @@
15
15
  "noImplicitAny": false,
16
16
  "noEmit": true,
17
17
  "paths": {
18
- "@src/*": ["./src/*"],
18
+ "@src/*": ["./src/*"]
19
19
  }
20
- }
20
+ },
21
+ "include": ["src"]
21
22
  }