@xswap-link/sdk 0.6.10 → 0.8.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.
- package/CHANGELOG.md +16 -0
- package/dist/index.d.mts +124 -72
- package/dist/index.d.ts +124 -72
- package/dist/index.global.js +686 -281
- package/dist/index.js +10 -10
- package/dist/index.mjs +10 -10
- package/package.json +1 -1
- package/src/assets/icons/ArrowsExchange.tsx +18 -0
- package/src/assets/icons/index.ts +1 -0
- package/src/components/Modal/index.tsx +48 -41
- package/src/components/Swap/Header/index.tsx +4 -2
- package/src/components/Swap/HistoryView/index.tsx +2 -2
- package/src/components/Swap/ReorderButton/ReorderButton.tsx +37 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon.tsx +1 -1
- package/src/components/Swap/SwapView/SwapButton/index.tsx +31 -22
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +55 -22
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +74 -10
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +83 -28
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +9 -5
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +12 -6
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +50 -29
- package/src/components/Swap/SwapView/SwapPanel/index.tsx +8 -3
- package/src/components/Swap/SwapView/WalletPicker/index.tsx +7 -6
- package/src/components/Swap/SwapView/index.tsx +3 -3
- package/src/components/Swap/index.tsx +1 -1
- package/src/components/TxConfigForm/index.tsx +69 -19
- package/src/components/TxModal/index.tsx +59 -0
- package/src/components/TxWidgetWC/index.tsx +47 -2
- package/src/components/TxWidgetWCWrapped/index.tsx +33 -1
- package/src/components/index.ts +1 -0
- package/src/config/index.ts +1 -1
- package/src/context/SwapProvider.tsx +177 -27
- package/src/context/TxUIWrapper.tsx +5 -5
- package/src/hooks/index.ts +0 -1
- package/src/models/BridgeTokensDictionary.ts +7 -0
- package/src/models/TokenData.ts +3 -1
- package/src/models/index.ts +6 -5
- package/src/models/payloads/ModalIntegrationPayload.ts +17 -3
- package/src/models/payloads/WidgetIntegrationPayload.ts +15 -1
- package/src/services/api.ts +6 -1
- package/src/services/integrations/transactions.ts +40 -17
- package/src/types/global.d.ts +15 -0
- package/src/utils/validation.ts +367 -0
- package/tsconfig.json +3 -2
- package/src/context/ModalProvider.tsx +0 -63
- package/src/hooks/usePortal.ts +0 -79
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { xpayShadowRoot } from "@src/config";
|
|
2
|
+
import { MouseEvent, ReactElement } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
|
|
5
|
+
export type TxModalType =
|
|
6
|
+
| "neutral"
|
|
7
|
+
| "waiting"
|
|
8
|
+
| "warning"
|
|
9
|
+
| "error"
|
|
10
|
+
| "success";
|
|
11
|
+
|
|
12
|
+
type Props = {
|
|
13
|
+
id: string;
|
|
14
|
+
children: ReactElement | ReactElement[];
|
|
15
|
+
onCloseClick: () => void;
|
|
16
|
+
type?: TxModalType;
|
|
17
|
+
className?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const TxModal = ({
|
|
21
|
+
id,
|
|
22
|
+
children,
|
|
23
|
+
onCloseClick,
|
|
24
|
+
type = "waiting",
|
|
25
|
+
className,
|
|
26
|
+
}: Props) => {
|
|
27
|
+
const onBackdropClick = (e: MouseEvent<HTMLDivElement>) => {
|
|
28
|
+
e.stopPropagation();
|
|
29
|
+
e.nativeEvent.stopImmediatePropagation();
|
|
30
|
+
if (e.target === e.currentTarget) {
|
|
31
|
+
onCloseClick();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return createPortal(
|
|
36
|
+
<div
|
|
37
|
+
className="fixed box-border inset-0 z-20 flex items-center justify-center bg-black bg-opacity-80"
|
|
38
|
+
onMouseDown={onBackdropClick}
|
|
39
|
+
>
|
|
40
|
+
<div
|
|
41
|
+
className={`relative bg-t_bg_primary rounded-3xl p-4 w-full min-w-[340px] overflow-auto max-w-x_modal border-2 ${
|
|
42
|
+
type === "error"
|
|
43
|
+
? "border-t_error_dark"
|
|
44
|
+
: type === "success"
|
|
45
|
+
? "border-t_success_dark"
|
|
46
|
+
: type === "warning"
|
|
47
|
+
? "border-t_warning_dark"
|
|
48
|
+
: type === "waiting"
|
|
49
|
+
? "border-t_main_accent_dark"
|
|
50
|
+
: "border-t_text_primary border-opacity-10"
|
|
51
|
+
} ${className}`}
|
|
52
|
+
>
|
|
53
|
+
{children}
|
|
54
|
+
</div>
|
|
55
|
+
</div>,
|
|
56
|
+
xpayShadowRoot!,
|
|
57
|
+
id,
|
|
58
|
+
);
|
|
59
|
+
};
|
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
WidgetIntegrationPayload,
|
|
6
6
|
} from "@src/models";
|
|
7
7
|
import { getChains } from "@src/services";
|
|
8
|
+
import { isServer } from "@src/utils";
|
|
8
9
|
import { createWebComponent } from "@src/utils/webComponents";
|
|
9
10
|
import { useEffect, useState } from "react";
|
|
10
11
|
import { Spinner } from "../Spinner";
|
|
11
12
|
import { TxConfigForm } from "../TxConfigForm";
|
|
12
13
|
import CSS from "../global.css";
|
|
13
|
-
import { isServer } from "@src/utils";
|
|
14
14
|
|
|
15
15
|
const TxWidget = ({
|
|
16
16
|
integratorId,
|
|
@@ -24,6 +24,16 @@ const TxWidget = ({
|
|
|
24
24
|
lightTheme,
|
|
25
25
|
defaultWalletPicker,
|
|
26
26
|
styles,
|
|
27
|
+
onPendingTransactionsChange,
|
|
28
|
+
dstTokenLocked,
|
|
29
|
+
dstChainLocked,
|
|
30
|
+
srcTokenLocked,
|
|
31
|
+
srcChainLocked,
|
|
32
|
+
onDstTokenChange,
|
|
33
|
+
onDstChainChange,
|
|
34
|
+
onSrcTokenChange,
|
|
35
|
+
onSrcChainChange,
|
|
36
|
+
bridge,
|
|
27
37
|
}: WidgetIntegrationPayload) => {
|
|
28
38
|
const [loading, setLoading] = useState(true);
|
|
29
39
|
const [supportedChains, setSupportedChains] = useState<Chain[]>([]);
|
|
@@ -57,7 +67,9 @@ const TxWidget = ({
|
|
|
57
67
|
<style>{CSS}</style>
|
|
58
68
|
|
|
59
69
|
{loading ? (
|
|
60
|
-
<
|
|
70
|
+
<div className="min-h-[532px] w-full flex items-center justify-center">
|
|
71
|
+
<Spinner className="w-10 h-10" />
|
|
72
|
+
</div>
|
|
61
73
|
) : (
|
|
62
74
|
<TxConfigForm
|
|
63
75
|
integratorId={integratorId}
|
|
@@ -73,6 +85,16 @@ const TxWidget = ({
|
|
|
73
85
|
lightTheme={lightTheme}
|
|
74
86
|
defaultWalletPicker={defaultWalletPicker}
|
|
75
87
|
styles={parsedStyles}
|
|
88
|
+
onPendingTransactionsChange={onPendingTransactionsChange}
|
|
89
|
+
dstTokenLocked={dstTokenLocked}
|
|
90
|
+
dstChainLocked={dstChainLocked}
|
|
91
|
+
srcTokenLocked={srcTokenLocked}
|
|
92
|
+
srcChainLocked={srcChainLocked}
|
|
93
|
+
onDstTokenChange={onDstTokenChange}
|
|
94
|
+
onDstChainChange={onDstChainChange}
|
|
95
|
+
onSrcTokenChange={onSrcTokenChange}
|
|
96
|
+
onSrcChainChange={onSrcChainChange}
|
|
97
|
+
bridge={bridge}
|
|
76
98
|
/>
|
|
77
99
|
)}
|
|
78
100
|
</>
|
|
@@ -106,6 +128,16 @@ export const createTxWidgetWC = () => {
|
|
|
106
128
|
lightTheme: "boolean",
|
|
107
129
|
defaultWalletPicker: "boolean",
|
|
108
130
|
styles: "json",
|
|
131
|
+
onPendingTransactionsChange: "function",
|
|
132
|
+
dstTokenLocked: "boolean",
|
|
133
|
+
dstChainLocked: "boolean",
|
|
134
|
+
srcTokenLocked: "boolean",
|
|
135
|
+
srcChainLocked: "boolean",
|
|
136
|
+
bridge: "boolean",
|
|
137
|
+
onDstTokenChange: "function",
|
|
138
|
+
onDstChainChange: "function",
|
|
139
|
+
onSrcTokenChange: "function",
|
|
140
|
+
onSrcChainChange: "function",
|
|
109
141
|
},
|
|
110
142
|
});
|
|
111
143
|
|
|
@@ -116,6 +148,8 @@ export const createTxWidgetWC = () => {
|
|
|
116
148
|
return TxWidgetWC;
|
|
117
149
|
};
|
|
118
150
|
|
|
151
|
+
// Most fields are required here to enforce adding them in TxWidgetWCWrapped.
|
|
152
|
+
// callbacks are optional, because it will not be passed in TxWidgetWCWrapped.
|
|
119
153
|
export type TxWidgetWCAttributes = {
|
|
120
154
|
"integrator-id": WidgetIntegrationPayload["integratorId"];
|
|
121
155
|
"dst-chain": WidgetIntegrationPayload["dstChain"];
|
|
@@ -128,4 +162,15 @@ export type TxWidgetWCAttributes = {
|
|
|
128
162
|
"light-theme": WidgetIntegrationPayload["lightTheme"];
|
|
129
163
|
"default-wallet-picker": WidgetIntegrationPayload["defaultWalletPicker"];
|
|
130
164
|
styles: string | undefined;
|
|
165
|
+
"on-pending-transactions-change"?:
|
|
166
|
+
| WidgetIntegrationPayload["onPendingTransactionsChange"];
|
|
167
|
+
"dst-token-locked": WidgetIntegrationPayload["dstTokenLocked"] | undefined;
|
|
168
|
+
"dst-chain-locked": WidgetIntegrationPayload["dstChainLocked"] | undefined;
|
|
169
|
+
"src-token-locked": WidgetIntegrationPayload["srcTokenLocked"] | undefined;
|
|
170
|
+
"src-chain-locked": WidgetIntegrationPayload["srcChainLocked"] | undefined;
|
|
171
|
+
"on-dst-token-change"?: WidgetIntegrationPayload["onDstTokenChange"];
|
|
172
|
+
"on-dst-chain-change"?: WidgetIntegrationPayload["onDstChainChange"];
|
|
173
|
+
"on-src-token-change"?: WidgetIntegrationPayload["onSrcTokenChange"];
|
|
174
|
+
"on-src-chain-change"?: WidgetIntegrationPayload["onSrcChainChange"];
|
|
175
|
+
bridge: WidgetIntegrationPayload["bridge"] | undefined;
|
|
131
176
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WidgetIntegrationPayload } from "@src/models";
|
|
2
|
-
import { createTxWidgetWC, TxWidgetWCAttributes } from "../TxWidgetWC";
|
|
3
2
|
import { isServer } from "@tanstack/react-query";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { createTxWidgetWC, TxWidgetWCAttributes } from "../TxWidgetWC";
|
|
4
5
|
|
|
5
6
|
const TxWidgetWC = createTxWidgetWC();
|
|
6
7
|
|
|
@@ -35,7 +36,33 @@ export const TxWidgetWCWrapped = ({
|
|
|
35
36
|
lightTheme,
|
|
36
37
|
defaultWalletPicker,
|
|
37
38
|
styles,
|
|
39
|
+
onPendingTransactionsChange,
|
|
40
|
+
dstTokenLocked,
|
|
41
|
+
dstChainLocked,
|
|
42
|
+
srcTokenLocked,
|
|
43
|
+
srcChainLocked,
|
|
44
|
+
onDstTokenChange,
|
|
45
|
+
onDstChainChange,
|
|
46
|
+
onSrcTokenChange,
|
|
47
|
+
onSrcChainChange,
|
|
48
|
+
bridge,
|
|
38
49
|
}: WidgetIntegrationPayload) => {
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
// We couldn't find a way to pass a function to the web component created by @r2wc/core.
|
|
52
|
+
// It is assigned to window to be accessed later from within the web component.
|
|
53
|
+
window.xPayOnPendingTransactionsChange = onPendingTransactionsChange;
|
|
54
|
+
window.xPayOnDstTokenChange = onDstTokenChange;
|
|
55
|
+
window.xPayOnDstChainChange = onDstChainChange;
|
|
56
|
+
window.xPayOnSrcTokenChange = onSrcTokenChange;
|
|
57
|
+
window.xPayOnSrcChainChange = onSrcChainChange;
|
|
58
|
+
}, [
|
|
59
|
+
onPendingTransactionsChange,
|
|
60
|
+
onDstTokenChange,
|
|
61
|
+
onDstChainChange,
|
|
62
|
+
onSrcTokenChange,
|
|
63
|
+
onSrcChainChange,
|
|
64
|
+
]);
|
|
65
|
+
|
|
39
66
|
return (
|
|
40
67
|
<xpay-widget
|
|
41
68
|
integrator-id={integratorId}
|
|
@@ -49,6 +76,11 @@ export const TxWidgetWCWrapped = ({
|
|
|
49
76
|
light-theme={lightTheme}
|
|
50
77
|
default-wallet-picker={defaultWalletPicker}
|
|
51
78
|
styles={typeof styles === "string" ? styles : JSON.stringify(styles)}
|
|
79
|
+
dst-token-locked={dstTokenLocked}
|
|
80
|
+
dst-chain-locked={dstChainLocked}
|
|
81
|
+
src-token-locked={srcTokenLocked}
|
|
82
|
+
src-chain-locked={srcChainLocked}
|
|
83
|
+
bridge={bridge}
|
|
52
84
|
></xpay-widget>
|
|
53
85
|
);
|
|
54
86
|
};
|
package/src/components/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export * from "./TokenLogo/WithChain";
|
|
|
17
17
|
export * from "./Tooltip";
|
|
18
18
|
export * from "./TxConfigForm";
|
|
19
19
|
export * from "./TxDataCard";
|
|
20
|
+
export * from "./TxModal";
|
|
20
21
|
export * from "./TxStatusButton";
|
|
21
22
|
export * from "./TxWidgetWC";
|
|
22
23
|
export * from "./TxWidgetWCWrapped";
|
package/src/config/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
} from "@src/constants";
|
|
9
9
|
import { ADDRESSES } from "@src/contracts";
|
|
10
10
|
import {
|
|
11
|
+
BridgeToken,
|
|
12
|
+
BridgeTokensDictionary,
|
|
11
13
|
Chain,
|
|
12
14
|
Route,
|
|
13
15
|
Token,
|
|
@@ -16,7 +18,12 @@ import {
|
|
|
16
18
|
Transaction,
|
|
17
19
|
Web3Environment,
|
|
18
20
|
} from "@src/models";
|
|
19
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
getBalances,
|
|
23
|
+
getBridgeTokens,
|
|
24
|
+
getPrices,
|
|
25
|
+
getRoute,
|
|
26
|
+
} from "@src/services";
|
|
20
27
|
import {
|
|
21
28
|
deepMergeObjects,
|
|
22
29
|
getBalanceOf,
|
|
@@ -25,6 +32,7 @@ import {
|
|
|
25
32
|
safeBigNumberFrom,
|
|
26
33
|
weiToHumanReadable,
|
|
27
34
|
} from "@src/utils";
|
|
35
|
+
import { mapToValidPath } from "@src/utils/validation";
|
|
28
36
|
import BigNumberJS from "bignumber.js";
|
|
29
37
|
import { BigNumber, constants } from "ethers";
|
|
30
38
|
import {
|
|
@@ -44,6 +52,7 @@ import { useHistory } from "./HistoryProvider";
|
|
|
44
52
|
|
|
45
53
|
type Tab = "Swap" | "History" | "Settings";
|
|
46
54
|
type SwapContext = {
|
|
55
|
+
bridgeUI: boolean;
|
|
47
56
|
integrationConfig: Partial<TxConfigFormPayload>;
|
|
48
57
|
wagmiConfig: Config;
|
|
49
58
|
supportedChains: Chain[];
|
|
@@ -53,22 +62,22 @@ type SwapContext = {
|
|
|
53
62
|
error: string;
|
|
54
63
|
setError: Dispatch<SetStateAction<string>>;
|
|
55
64
|
feeToken: Token | undefined;
|
|
56
|
-
srcChainProvided: boolean;
|
|
57
65
|
srcChain: Chain | undefined;
|
|
58
66
|
setSrcChain: Dispatch<SetStateAction<Chain | undefined>>;
|
|
59
67
|
srcChainTokensOptions: TokenOption[];
|
|
60
68
|
srcChainOtherTokensOptions: TokenOption[];
|
|
61
69
|
srcChainTokensPrices: TokenPrices;
|
|
62
70
|
dstChainTokensPrices: TokenPrices;
|
|
63
|
-
srcTokenProvided: boolean;
|
|
64
71
|
srcToken: Token | undefined;
|
|
65
72
|
setSrcToken: Dispatch<SetStateAction<Token | undefined>>;
|
|
66
|
-
dstChainProvided: boolean;
|
|
67
73
|
dstChain: Chain | undefined;
|
|
68
74
|
setDstChain: Dispatch<SetStateAction<Chain | undefined>>;
|
|
69
75
|
dstChainTokensOptions: TokenOption[];
|
|
70
76
|
dstChainOtherTokensOptions: TokenOption[];
|
|
71
|
-
|
|
77
|
+
dstTokenLocked: boolean;
|
|
78
|
+
dstChainLocked?: boolean;
|
|
79
|
+
srcTokenLocked?: boolean;
|
|
80
|
+
srcChainLocked?: boolean;
|
|
72
81
|
dstToken: Token | undefined;
|
|
73
82
|
setDstToken: Dispatch<SetStateAction<Token | undefined>>;
|
|
74
83
|
srcValue: string;
|
|
@@ -102,6 +111,7 @@ type SwapContext = {
|
|
|
102
111
|
tokenAddress: string,
|
|
103
112
|
chainId: string,
|
|
104
113
|
) => Token | undefined;
|
|
114
|
+
bridgeTokensDictionary: BridgeTokensDictionary | null;
|
|
105
115
|
};
|
|
106
116
|
|
|
107
117
|
const functionNotImplemented = () => {
|
|
@@ -109,6 +119,7 @@ const functionNotImplemented = () => {
|
|
|
109
119
|
};
|
|
110
120
|
|
|
111
121
|
const init: SwapContext = {
|
|
122
|
+
bridgeUI: false,
|
|
112
123
|
integrationConfig: {},
|
|
113
124
|
wagmiConfig: {} as Config,
|
|
114
125
|
supportedChains: [],
|
|
@@ -116,19 +127,19 @@ const init: SwapContext = {
|
|
|
116
127
|
overlay: false,
|
|
117
128
|
error: "",
|
|
118
129
|
feeToken: undefined,
|
|
119
|
-
srcChainProvided: false,
|
|
120
130
|
srcChain: undefined,
|
|
121
131
|
srcChainTokensOptions: [],
|
|
122
132
|
srcChainOtherTokensOptions: [],
|
|
123
133
|
srcChainTokensPrices: {},
|
|
124
134
|
dstChainTokensPrices: {},
|
|
125
|
-
dstChainProvided: false,
|
|
126
135
|
dstChain: undefined,
|
|
127
136
|
dstChainTokensOptions: [],
|
|
128
137
|
dstChainOtherTokensOptions: [],
|
|
129
|
-
srcTokenProvided: false,
|
|
130
138
|
srcToken: undefined,
|
|
131
|
-
|
|
139
|
+
dstTokenLocked: false,
|
|
140
|
+
dstChainLocked: false,
|
|
141
|
+
srcTokenLocked: false,
|
|
142
|
+
srcChainLocked: false,
|
|
132
143
|
dstToken: undefined,
|
|
133
144
|
srcValue: "",
|
|
134
145
|
srcValueWei: "",
|
|
@@ -164,6 +175,7 @@ const init: SwapContext = {
|
|
|
164
175
|
quoteRoute: functionNotImplemented,
|
|
165
176
|
refreshBalance: functionNotImplemented,
|
|
166
177
|
findTokenDataByAddressAndChain: functionNotImplemented,
|
|
178
|
+
bridgeTokensDictionary: null,
|
|
167
179
|
};
|
|
168
180
|
|
|
169
181
|
const swapContext = createContext(init);
|
|
@@ -189,22 +201,28 @@ export const SwapProvider = ({
|
|
|
189
201
|
const [infiniteApproval, setInfiniteApproval] = useState(
|
|
190
202
|
init.infiniteApproval,
|
|
191
203
|
);
|
|
192
|
-
const
|
|
193
|
-
() => !!integrationConfig?.
|
|
194
|
-
[integrationConfig?.
|
|
204
|
+
const srcTokenLocked = useMemo(
|
|
205
|
+
() => !!integrationConfig?.srcTokenLocked,
|
|
206
|
+
[integrationConfig?.srcTokenLocked],
|
|
207
|
+
);
|
|
208
|
+
const dstTokenLocked = useMemo(
|
|
209
|
+
() => !!integrationConfig?.dstTokenLocked,
|
|
210
|
+
[integrationConfig?.dstTokenLocked],
|
|
195
211
|
);
|
|
196
|
-
const
|
|
197
|
-
() => !!integrationConfig?.
|
|
198
|
-
[integrationConfig?.
|
|
212
|
+
const srcChainLocked = useMemo(
|
|
213
|
+
() => !!integrationConfig?.srcChainLocked,
|
|
214
|
+
[integrationConfig?.srcChainLocked],
|
|
199
215
|
);
|
|
200
|
-
const
|
|
201
|
-
() => !!integrationConfig?.
|
|
202
|
-
[integrationConfig?.
|
|
216
|
+
const dstChainLocked = useMemo(
|
|
217
|
+
() => !!integrationConfig?.dstChainLocked,
|
|
218
|
+
[integrationConfig?.dstChainLocked],
|
|
203
219
|
);
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
220
|
+
|
|
221
|
+
const bridgeUI = useMemo(
|
|
222
|
+
() => !!integrationConfig.bridge,
|
|
223
|
+
[integrationConfig.bridge],
|
|
207
224
|
);
|
|
225
|
+
|
|
208
226
|
const [slippage, setSlippage] = useState(init.slippage);
|
|
209
227
|
const [srcChain, setSrcChain] = useState(init.srcChain);
|
|
210
228
|
const [dstChain, setDstChain] = useState(init.dstChain);
|
|
@@ -288,14 +306,66 @@ export const SwapProvider = ({
|
|
|
288
306
|
return tempChainToTokenOptionsMap;
|
|
289
307
|
}, [supportedTokens]);
|
|
290
308
|
|
|
309
|
+
const [bridgeTokens, setBridgeTokens] = useState<BridgeToken[]>([]);
|
|
310
|
+
useEffect(() => {
|
|
311
|
+
(async () => {
|
|
312
|
+
const data = await getBridgeTokens();
|
|
313
|
+
setBridgeTokens(data);
|
|
314
|
+
})();
|
|
315
|
+
}, []);
|
|
316
|
+
|
|
317
|
+
const bridgeTokensDictionary = useMemo(() => {
|
|
318
|
+
const result: BridgeTokensDictionary = {};
|
|
319
|
+
|
|
320
|
+
for (const dict of bridgeTokens) {
|
|
321
|
+
const [chainId0, address0] = Object.entries(dict)[0]!;
|
|
322
|
+
const [chainId1, address1] = Object.entries(dict)[1]!;
|
|
323
|
+
if (!result[chainId0]) {
|
|
324
|
+
result[chainId0] = {};
|
|
325
|
+
}
|
|
326
|
+
if (!result[chainId0][address0]) {
|
|
327
|
+
result[chainId0][address0] = {};
|
|
328
|
+
}
|
|
329
|
+
result[chainId0][address0][chainId1] = address1;
|
|
330
|
+
if (!result[chainId1]) {
|
|
331
|
+
result[chainId1] = {};
|
|
332
|
+
}
|
|
333
|
+
if (!result[chainId1][address1]) {
|
|
334
|
+
result[chainId1][address1] = {};
|
|
335
|
+
}
|
|
336
|
+
result[chainId1][address1][chainId0] = address0;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (Object.keys(result).length) {
|
|
340
|
+
return result;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return null;
|
|
344
|
+
}, [bridgeTokens]);
|
|
345
|
+
|
|
291
346
|
const getTokenOptions = useCallback(
|
|
292
|
-
(chainId: string, oppositeChainId: string) => {
|
|
347
|
+
(chainId: string | undefined, oppositeChainId: string | undefined) => {
|
|
293
348
|
if (!chainId || !oppositeChainId) {
|
|
294
349
|
return [];
|
|
295
350
|
}
|
|
351
|
+
|
|
352
|
+
if (bridgeTokensDictionary && bridgeUI) {
|
|
353
|
+
if (!chainToTokenOptionsMap[chainId]) {
|
|
354
|
+
return [];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return chainToTokenOptionsMap[chainId].filter((tokenData) => {
|
|
358
|
+
const supportedTokensAddresses = Object.keys(
|
|
359
|
+
bridgeTokensDictionary[chainId] || {},
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
return supportedTokensAddresses.includes(tokenData.address);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
296
366
|
return chainToTokenOptionsMap[chainId] || [];
|
|
297
367
|
},
|
|
298
|
-
[chainToTokenOptionsMap],
|
|
368
|
+
[bridgeTokensDictionary, bridgeUI, chainToTokenOptionsMap],
|
|
299
369
|
);
|
|
300
370
|
|
|
301
371
|
const srcTokenBalanceInfo = useMemo(() => {
|
|
@@ -665,9 +735,88 @@ export const SwapProvider = ({
|
|
|
665
735
|
setDstToken(initDstToken);
|
|
666
736
|
}, [integrationConfig, supportedChains]);
|
|
667
737
|
|
|
738
|
+
useEffect(() => {
|
|
739
|
+
if (!bridgeTokensDictionary) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const { source, target } = mapToValidPath({
|
|
744
|
+
source: { chain: srcChain, token: srcToken },
|
|
745
|
+
target: { chain: dstChain, token: dstToken },
|
|
746
|
+
type: bridgeUI ? "BRIDGE" : "SWAP",
|
|
747
|
+
supportedChains,
|
|
748
|
+
bridgeTokensDictionary,
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
if (source.chain?.chainId !== srcChain?.chainId) {
|
|
752
|
+
setSrcChain(source.chain);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (target.chain?.chainId !== dstChain?.chainId) {
|
|
756
|
+
setDstChain(target.chain);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
if (source.token?.address !== srcToken?.address) {
|
|
760
|
+
setSrcToken(source.token);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (target.token?.address !== dstToken?.address) {
|
|
764
|
+
setDstToken(target.token);
|
|
765
|
+
}
|
|
766
|
+
}, [
|
|
767
|
+
srcChain,
|
|
768
|
+
srcToken,
|
|
769
|
+
dstChain,
|
|
770
|
+
dstToken,
|
|
771
|
+
bridgeUI,
|
|
772
|
+
supportedChains,
|
|
773
|
+
bridgeTokensDictionary,
|
|
774
|
+
]);
|
|
775
|
+
|
|
776
|
+
useEffect(() => {
|
|
777
|
+
if (integrationConfig.onDstChainChange) {
|
|
778
|
+
integrationConfig.onDstChainChange(dstChain?.chainId);
|
|
779
|
+
} else if (window.xPayOnDstChainChange) {
|
|
780
|
+
window.xPayOnDstChainChange(dstChain?.chainId);
|
|
781
|
+
}
|
|
782
|
+
}, [integrationConfig, dstChain]);
|
|
783
|
+
|
|
784
|
+
useEffect(() => {
|
|
785
|
+
const token = dstToken
|
|
786
|
+
? { address: dstToken.address.toLowerCase(), symbol: dstToken.symbol }
|
|
787
|
+
: undefined;
|
|
788
|
+
|
|
789
|
+
if (integrationConfig.onDstTokenChange) {
|
|
790
|
+
integrationConfig.onDstTokenChange(token);
|
|
791
|
+
} else if (window.xPayOnDstTokenChange) {
|
|
792
|
+
window.xPayOnDstTokenChange(token);
|
|
793
|
+
}
|
|
794
|
+
}, [integrationConfig, dstToken]);
|
|
795
|
+
|
|
796
|
+
useEffect(() => {
|
|
797
|
+
if (integrationConfig.onSrcChainChange) {
|
|
798
|
+
integrationConfig.onSrcChainChange(srcChain?.chainId);
|
|
799
|
+
} else if (window.xPayOnSrcChainChange) {
|
|
800
|
+
window.xPayOnSrcChainChange(srcChain?.chainId);
|
|
801
|
+
}
|
|
802
|
+
}, [integrationConfig, srcChain]);
|
|
803
|
+
|
|
804
|
+
useEffect(() => {
|
|
805
|
+
const token = srcToken
|
|
806
|
+
? { address: srcToken.address.toLowerCase(), symbol: srcToken.symbol }
|
|
807
|
+
: undefined;
|
|
808
|
+
|
|
809
|
+
if (integrationConfig.onSrcTokenChange) {
|
|
810
|
+
integrationConfig.onSrcTokenChange(token);
|
|
811
|
+
} else if (window.xPayOnSrcTokenChange) {
|
|
812
|
+
window.xPayOnSrcTokenChange(token);
|
|
813
|
+
}
|
|
814
|
+
}, [integrationConfig, srcToken]);
|
|
815
|
+
|
|
668
816
|
return (
|
|
669
817
|
<swapContext.Provider
|
|
670
818
|
value={{
|
|
819
|
+
bridgeUI,
|
|
671
820
|
integrationConfig,
|
|
672
821
|
wagmiConfig,
|
|
673
822
|
supportedChains,
|
|
@@ -677,22 +826,18 @@ export const SwapProvider = ({
|
|
|
677
826
|
error,
|
|
678
827
|
setError,
|
|
679
828
|
feeToken,
|
|
680
|
-
srcChainProvided,
|
|
681
829
|
srcChain,
|
|
682
830
|
setSrcChain,
|
|
683
831
|
srcChainTokensOptions,
|
|
684
832
|
srcChainOtherTokensOptions,
|
|
685
833
|
dstChainTokensPrices,
|
|
686
834
|
srcChainTokensPrices,
|
|
687
|
-
dstChainProvided,
|
|
688
835
|
dstChain,
|
|
689
836
|
setDstChain,
|
|
690
837
|
dstChainTokensOptions,
|
|
691
838
|
dstChainOtherTokensOptions,
|
|
692
|
-
srcTokenProvided,
|
|
693
839
|
srcToken,
|
|
694
840
|
setSrcToken,
|
|
695
|
-
dstTokenProvided,
|
|
696
841
|
dstToken,
|
|
697
842
|
setDstToken,
|
|
698
843
|
srcValue,
|
|
@@ -723,6 +868,11 @@ export const SwapProvider = ({
|
|
|
723
868
|
quoteRoute,
|
|
724
869
|
refreshBalance,
|
|
725
870
|
findTokenDataByAddressAndChain,
|
|
871
|
+
srcTokenLocked,
|
|
872
|
+
srcChainLocked,
|
|
873
|
+
dstTokenLocked,
|
|
874
|
+
dstChainLocked,
|
|
875
|
+
bridgeTokensDictionary,
|
|
726
876
|
}}
|
|
727
877
|
>
|
|
728
878
|
{children}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { CloseIcon } from "@src/assets/icons";
|
|
2
2
|
import {
|
|
3
3
|
Button,
|
|
4
|
-
Modal,
|
|
5
|
-
ModalType,
|
|
6
4
|
SnackMessage,
|
|
7
5
|
Spinner,
|
|
6
|
+
TxModal,
|
|
7
|
+
TxModalType,
|
|
8
8
|
} from "@src/components";
|
|
9
9
|
import { ConfirmationView } from "@src/components/Swap/SwapView/ConfirmationView";
|
|
10
10
|
import { CCIP_EXPLORER } from "@src/constants";
|
|
@@ -319,7 +319,7 @@ export const TxUIWrapper = ({ children }: Props) => {
|
|
|
319
319
|
isTxModalOpenRef.current = flag;
|
|
320
320
|
}, []);
|
|
321
321
|
|
|
322
|
-
const modalType:
|
|
322
|
+
const modalType: TxModalType = useMemo(
|
|
323
323
|
() =>
|
|
324
324
|
txError
|
|
325
325
|
? "error"
|
|
@@ -369,14 +369,14 @@ export const TxUIWrapper = ({ children }: Props) => {
|
|
|
369
369
|
return (
|
|
370
370
|
<TxUIWrapperContext.Provider value={state}>
|
|
371
371
|
{isTxModalOpen && (
|
|
372
|
-
<
|
|
372
|
+
<TxModal
|
|
373
373
|
id="tx_modal"
|
|
374
374
|
className="max-w-x_modal"
|
|
375
375
|
type={modalType}
|
|
376
376
|
onCloseClick={closeTxModal}
|
|
377
377
|
>
|
|
378
378
|
<ConfirmationView onCloseClick={closeTxModal} />
|
|
379
|
-
</
|
|
379
|
+
</TxModal>
|
|
380
380
|
)}
|
|
381
381
|
{children}
|
|
382
382
|
</TxUIWrapperContext.Provider>
|
package/src/hooks/index.ts
CHANGED
package/src/models/TokenData.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Web3Environment } from "./Web3Environment";
|
|
2
1
|
import { BigNumber } from "ethers";
|
|
2
|
+
import { Web3Environment } from "./Web3Environment";
|
|
3
3
|
|
|
4
4
|
export type Chain = {
|
|
5
5
|
ecosystem: string;
|
|
@@ -17,6 +17,8 @@ export type Chain = {
|
|
|
17
17
|
publicRpcUrls: string[];
|
|
18
18
|
privateRpcUrls?: string[];
|
|
19
19
|
scanApiURL?: string;
|
|
20
|
+
defaultDstChain?: string;
|
|
21
|
+
disabledForDestination?: string[];
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
export type Token = {
|
package/src/models/index.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export * from "./Addresses";
|
|
2
|
-
export * from "./XSwapConfig";
|
|
3
2
|
export * from "./BridgeToken";
|
|
4
|
-
export * from "./
|
|
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";
|