@xswap-link/sdk 0.10.1 → 0.10.3
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 +91 -104
- package/dist/index.js +8 -8
- package/dist/index.mjs +9 -9
- package/localTheme.ts +1 -0
- package/package.json +1 -1
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +11 -2
- package/src/components/TxConfigForm/index.tsx +60 -43
- 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();
|
|
@@ -29,6 +29,20 @@ export type TxConfigFormPayload = Omit<
|
|
|
29
29
|
integratorFeeReceiverAddress?: string;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
type TxConfigFormProps = TxConfigFormPayload &
|
|
33
|
+
(
|
|
34
|
+
| {
|
|
35
|
+
onSubmit: (route: Route) => void;
|
|
36
|
+
onClose: () => void;
|
|
37
|
+
overlay: true;
|
|
38
|
+
}
|
|
39
|
+
| {
|
|
40
|
+
onSubmit?: undefined;
|
|
41
|
+
onClose?: undefined;
|
|
42
|
+
overlay: false;
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
32
46
|
const queryClient = new QueryClient();
|
|
33
47
|
|
|
34
48
|
const WagmiReload: FC = () => {
|
|
@@ -52,6 +66,14 @@ const WagmiReload: FC = () => {
|
|
|
52
66
|
return <></>;
|
|
53
67
|
};
|
|
54
68
|
|
|
69
|
+
const normalizeTxConfigFormProps = (props: TxConfigFormProps) => {
|
|
70
|
+
return {
|
|
71
|
+
...props,
|
|
72
|
+
dstTokenAddr: props.dstTokenAddr?.toLowerCase(),
|
|
73
|
+
srcTokenAddr: props.srcTokenAddr?.toLowerCase(),
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
|
|
55
77
|
const PendingTransactionsEmitter: FC<{
|
|
56
78
|
onPendingTransactionsChange: ModalIntegrationPayload["onPendingTransactionsChange"];
|
|
57
79
|
}> = ({ onPendingTransactionsChange }) => {
|
|
@@ -73,49 +95,44 @@ const PendingTransactionsEmitter: FC<{
|
|
|
73
95
|
return <></>;
|
|
74
96
|
};
|
|
75
97
|
|
|
76
|
-
export const TxConfigForm = ({
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
onSubmit?: undefined;
|
|
115
|
-
onClose?: undefined;
|
|
116
|
-
overlay: false;
|
|
117
|
-
}
|
|
118
|
-
)) => {
|
|
98
|
+
export const TxConfigForm = (props: TxConfigFormProps) => {
|
|
99
|
+
const normalizedProps = useMemo(
|
|
100
|
+
() => normalizeTxConfigFormProps(props),
|
|
101
|
+
[props],
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const {
|
|
105
|
+
integratorId,
|
|
106
|
+
dstChainId,
|
|
107
|
+
dstTokenAddr,
|
|
108
|
+
srcChainId,
|
|
109
|
+
srcTokenAddr,
|
|
110
|
+
customContractCalls,
|
|
111
|
+
desc,
|
|
112
|
+
dstDisplayTokenAddr,
|
|
113
|
+
supportedChains,
|
|
114
|
+
onSubmit,
|
|
115
|
+
onClose,
|
|
116
|
+
overlay,
|
|
117
|
+
lightTheme,
|
|
118
|
+
defaultWalletPicker,
|
|
119
|
+
styles,
|
|
120
|
+
onPendingTransactionsChange,
|
|
121
|
+
dstTokenLocked,
|
|
122
|
+
dstChainLocked,
|
|
123
|
+
srcTokenLocked,
|
|
124
|
+
srcChainLocked,
|
|
125
|
+
onDstTokenChange,
|
|
126
|
+
onDstChainChange,
|
|
127
|
+
onSrcTokenChange,
|
|
128
|
+
onSrcChainChange,
|
|
129
|
+
bridge,
|
|
130
|
+
onConnectWallet,
|
|
131
|
+
override,
|
|
132
|
+
integratorFee,
|
|
133
|
+
integratorFeeReceiverAddress,
|
|
134
|
+
} = normalizedProps;
|
|
135
|
+
|
|
119
136
|
const onBackdropClick = (e: MouseEvent) => {
|
|
120
137
|
e.stopPropagation();
|
|
121
138
|
e.nativeEvent.stopImmediatePropagation();
|
|
@@ -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: {
|