@xswap-link/sdk 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.global.js +90 -103
- package/dist/index.js +8 -8
- package/dist/index.mjs +8 -8
- package/localTheme.ts +1 -0
- package/package.json +1 -1
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +19 -14
- package/src/components/TxConfigForm/index.tsx +2 -2
- package/src/components/TxWidgetWC/index.tsx +4 -1
- package/src/config/init.tsx +0 -1
- package/src/context/SwapProvider.tsx +29 -1
- package/src/models/payloads/ModalIntegrationPayload.ts +2 -1
- package/src/services/integrations/transactions.ts +2 -14
- package/src/utils/tokens.ts +52 -0
- package/tailwind.config.js +11 -3
package/localTheme.ts
CHANGED
|
@@ -108,6 +108,7 @@ const styleMap: ModalIntegrationThemeStyles & ModalIntegrationStyles = {
|
|
|
108
108
|
errorLight: "--error-light",
|
|
109
109
|
width: "--modal-width",
|
|
110
110
|
chainlinkLogo: "--chainlink-logo",
|
|
111
|
+
fontFamily: "--font-family",
|
|
111
112
|
};
|
|
112
113
|
|
|
113
114
|
export function changeHostVariableColor(
|
package/package.json
CHANGED
|
@@ -56,6 +56,7 @@ export const TokenPicker = ({
|
|
|
56
56
|
supportedChains,
|
|
57
57
|
findTokenDataByAddressAndChain,
|
|
58
58
|
tokenPrices,
|
|
59
|
+
addTokenToChainIfNotExists,
|
|
59
60
|
} = useSwapContext();
|
|
60
61
|
const { address } = useAccount();
|
|
61
62
|
const evmContractApi = useEvmContractApi();
|
|
@@ -93,10 +94,18 @@ export const TokenPicker = ({
|
|
|
93
94
|
};
|
|
94
95
|
localStorage.setItem("custom-tokens", JSON.stringify(customTokens));
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
+
|
|
98
|
+
addTokenToChainIfNotExists(newCustomToken.chainId, newCustomToken);
|
|
99
|
+
|
|
97
100
|
setModalOpen(false);
|
|
98
101
|
}
|
|
99
|
-
}, [
|
|
102
|
+
}, [
|
|
103
|
+
chain,
|
|
104
|
+
customTokenData,
|
|
105
|
+
searchValue,
|
|
106
|
+
addTokenToChainIfNotExists,
|
|
107
|
+
setModalOpen,
|
|
108
|
+
]);
|
|
100
109
|
|
|
101
110
|
const getCustomTokenData = useCallback(async () => {
|
|
102
111
|
const nonce = Date.now();
|
|
@@ -236,21 +245,21 @@ export const TokenPicker = ({
|
|
|
236
245
|
// Create groups based on chain and wallet connection status
|
|
237
246
|
const groups = chain
|
|
238
247
|
? [
|
|
239
|
-
...(!!address && ownedFilteredTokens.length
|
|
248
|
+
...(!!address && ownedFilteredTokens.length
|
|
240
249
|
? [ownedFilteredTokens]
|
|
241
250
|
: []),
|
|
242
251
|
currentChainTokens,
|
|
243
252
|
otherChainTokens,
|
|
244
253
|
]
|
|
245
254
|
: [
|
|
246
|
-
...(!!address && ownedFilteredTokens.length
|
|
255
|
+
...(!!address && ownedFilteredTokens.length
|
|
247
256
|
? [ownedFilteredTokens]
|
|
248
257
|
: []),
|
|
249
258
|
[...currentChainTokens, ...otherChainTokens],
|
|
250
259
|
];
|
|
251
260
|
|
|
252
261
|
return groups.flat();
|
|
253
|
-
}, [filteredTokens, otherFilteredTokens, chain, address,
|
|
262
|
+
}, [filteredTokens, otherFilteredTokens, chain, address, tokenPrices]);
|
|
254
263
|
|
|
255
264
|
const ownedTokens = useMemo(
|
|
256
265
|
() => allTokens.filter((token) => token.balance?.gt(0)),
|
|
@@ -260,19 +269,15 @@ export const TokenPicker = ({
|
|
|
260
269
|
const tokenGroups = useMemo(() => {
|
|
261
270
|
return chain
|
|
262
271
|
? [
|
|
263
|
-
...(
|
|
264
|
-
? [ownedTokens]
|
|
265
|
-
: []),
|
|
272
|
+
...(!!address && ownedTokens.length ? [ownedTokens] : []),
|
|
266
273
|
filteredTokens,
|
|
267
274
|
otherFilteredTokens,
|
|
268
275
|
]
|
|
269
276
|
: [
|
|
270
|
-
...(
|
|
271
|
-
? [ownedTokens]
|
|
272
|
-
: []),
|
|
277
|
+
...(!!address && ownedTokens.length ? [ownedTokens] : []),
|
|
273
278
|
otherFilteredTokens,
|
|
274
279
|
];
|
|
275
|
-
}, [chain,
|
|
280
|
+
}, [chain, address, ownedTokens, filteredTokens, otherFilteredTokens]);
|
|
276
281
|
|
|
277
282
|
return showImportWarning ? (
|
|
278
283
|
<>
|
|
@@ -465,7 +470,7 @@ export const TokenPicker = ({
|
|
|
465
470
|
if (!address) {
|
|
466
471
|
return `${chain.displayName} network`;
|
|
467
472
|
}
|
|
468
|
-
return ownedTokens.length
|
|
473
|
+
return ownedTokens.length
|
|
469
474
|
? "My tokens"
|
|
470
475
|
: `${chain.displayName} network`;
|
|
471
476
|
}
|
|
@@ -489,7 +494,7 @@ export const TokenPicker = ({
|
|
|
489
494
|
if (!address) {
|
|
490
495
|
return "All networks";
|
|
491
496
|
}
|
|
492
|
-
return ownedTokens.length
|
|
497
|
+
return ownedTokens.length
|
|
493
498
|
? "My tokens"
|
|
494
499
|
: "All networks";
|
|
495
500
|
}
|
|
@@ -245,9 +245,9 @@ export const openTxConfigForm = async ({
|
|
|
245
245
|
<TxConfigForm
|
|
246
246
|
integratorId={integratorId}
|
|
247
247
|
dstChainId={dstChainId}
|
|
248
|
-
dstTokenAddr={dstTokenAddr}
|
|
248
|
+
dstTokenAddr={dstTokenAddr?.toLowerCase()}
|
|
249
249
|
srcChainId={srcChainId}
|
|
250
|
-
srcTokenAddr={srcTokenAddr}
|
|
250
|
+
srcTokenAddr={srcTokenAddr?.toLowerCase()}
|
|
251
251
|
customContractCalls={customContractCalls}
|
|
252
252
|
desc={desc}
|
|
253
253
|
dstDisplayTokenAddr={dstDisplayTokenAddr}
|
|
@@ -11,6 +11,7 @@ import { useEffect, useState } from "react";
|
|
|
11
11
|
import { Spinner } from "../Spinner";
|
|
12
12
|
import { TxConfigForm } from "../TxConfigForm";
|
|
13
13
|
import CSS from "../global.css";
|
|
14
|
+
import { addCustomTokensToChains } from "@src/utils/tokens";
|
|
14
15
|
|
|
15
16
|
const TxWidget = ({
|
|
16
17
|
integratorId,
|
|
@@ -56,7 +57,9 @@ const TxWidget = ({
|
|
|
56
57
|
(bridgeSupported || swapSupported),
|
|
57
58
|
);
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
const chainsWithCustomTokens = addCustomTokensToChains(chains);
|
|
61
|
+
|
|
62
|
+
setSupportedChains(chainsWithCustomTokens);
|
|
60
63
|
setLoading(false);
|
|
61
64
|
})();
|
|
62
65
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
package/src/config/init.tsx
CHANGED
|
@@ -65,7 +65,6 @@ const createXPayRoot = async () => {
|
|
|
65
65
|
const xswapElement = document.createElement("div");
|
|
66
66
|
xpayShadowRoot = xswapElement.attachShadow({
|
|
67
67
|
mode: "open",
|
|
68
|
-
delegatesFocus: true,
|
|
69
68
|
});
|
|
70
69
|
xswapElement.setAttribute("id", "xpay-root");
|
|
71
70
|
document.body.appendChild(xswapElement);
|
|
@@ -117,6 +117,10 @@ type SwapContext = {
|
|
|
117
117
|
bridgeTokensDictionary: BridgeTokensDictionary | null;
|
|
118
118
|
onConnectWallet: () => void;
|
|
119
119
|
hasOnConnectWalletCallback: boolean;
|
|
120
|
+
addTokenToChainIfNotExists: (
|
|
121
|
+
chainId: string | undefined,
|
|
122
|
+
token: TokenOption,
|
|
123
|
+
) => void;
|
|
120
124
|
};
|
|
121
125
|
|
|
122
126
|
const functionNotImplemented = () => {
|
|
@@ -183,6 +187,7 @@ const init: SwapContext = {
|
|
|
183
187
|
hasOnConnectWalletCallback: false,
|
|
184
188
|
srcChainOptions: [],
|
|
185
189
|
dstChainOptions: [],
|
|
190
|
+
addTokenToChainIfNotExists: functionNotImplemented,
|
|
186
191
|
};
|
|
187
192
|
|
|
188
193
|
const swapContext = createContext(init);
|
|
@@ -668,6 +673,27 @@ export const SwapProvider = ({
|
|
|
668
673
|
}
|
|
669
674
|
}, [integrationConfig]);
|
|
670
675
|
|
|
676
|
+
const addTokenToChainIfNotExists = useCallback(
|
|
677
|
+
(chainId: string | undefined, token: TokenOption) => {
|
|
678
|
+
const chain = supportedChains.find((chain) => chain.chainId === chainId);
|
|
679
|
+
|
|
680
|
+
if (!chain) return chain;
|
|
681
|
+
|
|
682
|
+
const tokenExists = chain.tokens.some(
|
|
683
|
+
(existingToken) =>
|
|
684
|
+
existingToken.address.toLowerCase() === token.address.toLowerCase(),
|
|
685
|
+
);
|
|
686
|
+
|
|
687
|
+
const updated = tokenExists
|
|
688
|
+
? chain
|
|
689
|
+
: { ...chain, tokens: [...chain.tokens, token] };
|
|
690
|
+
|
|
691
|
+
setSrcChain(updated);
|
|
692
|
+
setSrcToken(token);
|
|
693
|
+
},
|
|
694
|
+
[supportedChains],
|
|
695
|
+
);
|
|
696
|
+
|
|
671
697
|
// =============================================================================
|
|
672
698
|
// Effects
|
|
673
699
|
// =============================================================================
|
|
@@ -987,7 +1013,8 @@ export const SwapProvider = ({
|
|
|
987
1013
|
}
|
|
988
1014
|
if (initDstChain) {
|
|
989
1015
|
initDstToken = initDstChain.tokens.find(
|
|
990
|
-
({ address }) =>
|
|
1016
|
+
({ address }) =>
|
|
1017
|
+
address.toLowerCase() === dstTokenAddress?.toLowerCase(),
|
|
991
1018
|
);
|
|
992
1019
|
}
|
|
993
1020
|
|
|
@@ -1182,6 +1209,7 @@ export const SwapProvider = ({
|
|
|
1182
1209
|
bridgeTokensDictionary,
|
|
1183
1210
|
onConnectWallet,
|
|
1184
1211
|
hasOnConnectWalletCallback,
|
|
1212
|
+
addTokenToChainIfNotExists,
|
|
1185
1213
|
}}
|
|
1186
1214
|
>
|
|
1187
1215
|
{children}
|
|
@@ -30,11 +30,12 @@ export type ModalIntegrationThemeStyles = {
|
|
|
30
30
|
errorDark?: string;
|
|
31
31
|
errorLight?: string;
|
|
32
32
|
chainlinkLogo?: string;
|
|
33
|
+
fontFamily?: string;
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
export type ModalIntegrationStyles = Pick<
|
|
36
37
|
ModalIntegrationThemeStyles,
|
|
37
|
-
"mainAccentLight" | "mainAccentDark" | "textSecondary"
|
|
38
|
+
"mainAccentLight" | "mainAccentDark" | "textSecondary" | "fontFamily"
|
|
38
39
|
> & { width?: string };
|
|
39
40
|
|
|
40
41
|
export type ModalIntegrationPayload = {
|
|
@@ -87,13 +87,7 @@ const validateSwapTxData = (
|
|
|
87
87
|
if (!supportedDstChain) {
|
|
88
88
|
throw new Error(`Provided chain '${dstChain}' is not supported`);
|
|
89
89
|
}
|
|
90
|
-
if (
|
|
91
|
-
dstToken &&
|
|
92
|
-
(!isETHAddressValid(dstToken) ||
|
|
93
|
-
supportedDstChain.tokens.findIndex(
|
|
94
|
-
({ address }) => address.toLowerCase() === dstToken.toLowerCase(),
|
|
95
|
-
) === -1)
|
|
96
|
-
) {
|
|
90
|
+
if (dstToken && !isETHAddressValid(dstToken)) {
|
|
97
91
|
throw new Error(
|
|
98
92
|
`Provided token address ${dstToken} on chain ${dstChain} is invalid`,
|
|
99
93
|
);
|
|
@@ -107,13 +101,7 @@ const validateSwapTxData = (
|
|
|
107
101
|
if (!supportedSrcChain) {
|
|
108
102
|
throw new Error(`Provided chain '${srcChain}' is not supported`);
|
|
109
103
|
}
|
|
110
|
-
if (
|
|
111
|
-
srcToken &&
|
|
112
|
-
(!isETHAddressValid(srcToken) ||
|
|
113
|
-
supportedSrcChain.tokens.findIndex(
|
|
114
|
-
({ address }) => address.toLowerCase() === srcToken.toLowerCase(),
|
|
115
|
-
) === -1)
|
|
116
|
-
) {
|
|
104
|
+
if (srcToken && !isETHAddressValid(srcToken)) {
|
|
117
105
|
throw new Error(
|
|
118
106
|
`Provided token address ${srcToken} on chain ${srcChain} is invalid`,
|
|
119
107
|
);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Chain, Token } from "@src/models";
|
|
2
|
+
import { isServer } from "@src/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Retrieves custom tokens from localStorage and adds them to the provided chains
|
|
6
|
+
* @param chains - The original chains to which custom tokens should be added
|
|
7
|
+
* @returns A new array of chains with custom tokens added
|
|
8
|
+
*/
|
|
9
|
+
export const addCustomTokensToChains = (chains: Chain[]): Chain[] => {
|
|
10
|
+
const customTokensObj = !isServer
|
|
11
|
+
? JSON.parse(localStorage.getItem("custom-tokens") || "{}")
|
|
12
|
+
: {};
|
|
13
|
+
|
|
14
|
+
const customTokens = Object.entries(customTokensObj).reduce(
|
|
15
|
+
(acc, [chainId, tokensObj]) => {
|
|
16
|
+
acc[chainId] = Object.values(tokensObj as Record<string, Token>);
|
|
17
|
+
return acc;
|
|
18
|
+
},
|
|
19
|
+
{} as Record<string, Token[]>,
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
return chains.map((chain) => {
|
|
23
|
+
const chainCustomTokens = customTokens[chain.chainId] || [];
|
|
24
|
+
|
|
25
|
+
if (chainCustomTokens.length === 0) {
|
|
26
|
+
return chain;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const filteredCustomTokens = chainCustomTokens.filter(
|
|
30
|
+
(customToken: Token) =>
|
|
31
|
+
!chain.tokens.some(
|
|
32
|
+
(existingToken) =>
|
|
33
|
+
existingToken.address.toLowerCase() ===
|
|
34
|
+
customToken.address.toLowerCase(),
|
|
35
|
+
),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (filteredCustomTokens.length === 0) {
|
|
39
|
+
return chain;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
...chain,
|
|
44
|
+
tokens: [
|
|
45
|
+
...chain.tokens,
|
|
46
|
+
...filteredCustomTokens.map((customToken: Token) => ({
|
|
47
|
+
...customToken,
|
|
48
|
+
})),
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
};
|
package/tailwind.config.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
/** @type {import("tailwindcss").Config} */
|
|
2
2
|
|
|
3
|
+
const withFontVariable = (fallback) => `var(--font-family, ${fallback})`;
|
|
4
|
+
|
|
3
5
|
export default {
|
|
4
6
|
content: ["src/components/**/*.{ts,tsx}", "src/context/**/*.{ts,tsx}"],
|
|
5
7
|
theme: {
|
|
6
8
|
fontFamily: {
|
|
7
|
-
body: [
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
body: [
|
|
10
|
+
withFontVariable("'Satoshi-Medium', Tahoma, Verdana, ui-sans-serif"),
|
|
11
|
+
],
|
|
12
|
+
sans: [
|
|
13
|
+
withFontVariable("'Satoshi-Medium', Tahoma, Verdana, ui-sans-serif"),
|
|
14
|
+
],
|
|
15
|
+
"sans-bold": [
|
|
16
|
+
withFontVariable("'Satoshi-Bold', Tahoma, Verdana, ui-sans-serif"),
|
|
17
|
+
],
|
|
10
18
|
},
|
|
11
19
|
extend: {
|
|
12
20
|
colors: {
|