@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
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { ArrowDownIcon } from "@src/assets/icons";
|
|
2
|
+
import { Modal } from "@src/components/Modal";
|
|
2
3
|
import { useSwapContext } from "@src/context";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { useCallback, useEffect } from "react";
|
|
4
|
+
import { Chain, Token } from "@src/models";
|
|
5
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
6
6
|
import { useAccount } from "wagmi";
|
|
7
7
|
import { SwapPanelType } from "../../../SwapView";
|
|
8
8
|
import { ChainPicker } from "./ChainPicker";
|
|
9
|
-
import { useMemo } from "react";
|
|
10
9
|
|
|
11
10
|
type Props = {
|
|
12
11
|
chain: Chain | undefined;
|
|
13
12
|
type: SwapPanelType;
|
|
13
|
+
className?: string;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export const ChainPanel = ({ chain, type }: Props) => {
|
|
16
|
+
export const ChainPanel = ({ chain, type, className }: Props) => {
|
|
17
17
|
const {
|
|
18
18
|
supportedChains,
|
|
19
19
|
srcChain,
|
|
@@ -23,20 +23,28 @@ export const ChainPanel = ({ chain, type }: Props) => {
|
|
|
23
23
|
setSrcToken,
|
|
24
24
|
dstToken,
|
|
25
25
|
setDstToken,
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
srcChainLocked,
|
|
27
|
+
dstChainLocked,
|
|
28
|
+
integrationConfig,
|
|
29
|
+
bridgeUI,
|
|
30
|
+
bridgeTokensDictionary,
|
|
28
31
|
} = useSwapContext();
|
|
29
32
|
|
|
30
33
|
const { chainId } = useAccount();
|
|
31
34
|
|
|
32
|
-
const
|
|
33
|
-
() => type === "destination" &&
|
|
34
|
-
[type,
|
|
35
|
+
const projectLockedDestinationChain = useMemo(
|
|
36
|
+
() => type === "destination" && dstChainLocked,
|
|
37
|
+
[type, dstChainLocked],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const projectLockedSourceChain = useMemo(
|
|
41
|
+
() => type === "source" && srcChainLocked,
|
|
42
|
+
[type, srcChainLocked],
|
|
35
43
|
);
|
|
36
44
|
|
|
37
45
|
// select chain from user wallet
|
|
38
46
|
useEffect(() => {
|
|
39
|
-
if (!chainId ||
|
|
47
|
+
if (!chainId || integrationConfig.srcChainId) return;
|
|
40
48
|
|
|
41
49
|
const userChainFromWallet = supportedChains.find(
|
|
42
50
|
(chain) => chain.chainId === String(chainId),
|
|
@@ -51,17 +59,61 @@ export const ChainPanel = ({ chain, type }: Props) => {
|
|
|
51
59
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
52
60
|
}, [chainId]);
|
|
53
61
|
|
|
54
|
-
const
|
|
62
|
+
const [chainPickerModalOpen, setChainPickerModalOpen] = useState(false);
|
|
55
63
|
|
|
56
64
|
const handleSrcChainChange = useCallback(
|
|
57
65
|
(chain: Chain) => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
let newSrcToken: Token | undefined = undefined;
|
|
67
|
+
|
|
68
|
+
if (bridgeUI) {
|
|
69
|
+
const bridgeableTokensAddresses = Object.keys(
|
|
70
|
+
bridgeTokensDictionary?.[chain.chainId] || {},
|
|
71
|
+
).map((address) => address.toLowerCase());
|
|
72
|
+
|
|
73
|
+
// Attempt to use the same token on a new chain matching by symbol.
|
|
74
|
+
newSrcToken = chain.tokens.find(
|
|
75
|
+
(token) =>
|
|
76
|
+
token.symbol === srcToken?.symbol &&
|
|
77
|
+
bridgeableTokensAddresses.includes(token.address.toLowerCase()),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (!newSrcToken) {
|
|
81
|
+
// The token from the previous chain is not bridgeable on the new chain.
|
|
82
|
+
// We will use the first available bridgeable token on the new chain.
|
|
83
|
+
|
|
84
|
+
const firstAvailableBridgeableTokenAddress =
|
|
85
|
+
bridgeableTokensAddresses[0];
|
|
86
|
+
|
|
87
|
+
if (!firstAvailableBridgeableTokenAddress) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Couldn't find any available bridgeable token on the chain ${chain.chainId}, but bridging is available`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
newSrcToken = chain.tokens.find(
|
|
94
|
+
(token) =>
|
|
95
|
+
token.address.toLowerCase() ===
|
|
96
|
+
firstAvailableBridgeableTokenAddress.toLowerCase(),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (!newSrcToken) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Found bridgeable token (${firstAvailableBridgeableTokenAddress}) on the chain ${chain.chainId}, but token was not defined in chains collection`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
newSrcToken =
|
|
107
|
+
// Attempt to use the same token on a new chain.
|
|
108
|
+
chain.tokens.find((token) => token.symbol === srcToken?.symbol) ||
|
|
109
|
+
// Otherwise, use the default token on this chain.
|
|
110
|
+
chain.tokens.find((token) => token.symbol === chain.tokenSymbol);
|
|
111
|
+
}
|
|
112
|
+
|
|
61
113
|
setSrcChain(chain);
|
|
62
114
|
setSrcToken(newSrcToken);
|
|
63
115
|
},
|
|
64
|
-
[setSrcChain, setSrcToken, srcToken],
|
|
116
|
+
[setSrcChain, setSrcToken, srcToken, bridgeTokensDictionary, bridgeUI],
|
|
65
117
|
);
|
|
66
118
|
|
|
67
119
|
const handleDstChainChange = useCallback(
|
|
@@ -77,19 +129,22 @@ export const ChainPanel = ({ chain, type }: Props) => {
|
|
|
77
129
|
|
|
78
130
|
return (
|
|
79
131
|
<>
|
|
132
|
+
{chainPickerModalOpen && (
|
|
133
|
+
<Modal onClose={() => setChainPickerModalOpen(false)}>
|
|
134
|
+
<ChainPicker
|
|
135
|
+
type={type}
|
|
136
|
+
setSrcChain={handleSrcChainChange}
|
|
137
|
+
setDstChain={handleDstChainChange}
|
|
138
|
+
onClose={() => setChainPickerModalOpen(false)}
|
|
139
|
+
/>
|
|
140
|
+
</Modal>
|
|
141
|
+
)}
|
|
142
|
+
|
|
80
143
|
<button
|
|
81
144
|
type="button"
|
|
82
|
-
disabled={
|
|
83
|
-
onClick={() =>
|
|
84
|
-
|
|
85
|
-
<ChainPicker
|
|
86
|
-
type={type}
|
|
87
|
-
supportedChains={supportedChains}
|
|
88
|
-
setSrcChain={handleSrcChainChange}
|
|
89
|
-
setDstChain={handleDstChainChange}
|
|
90
|
-
/>,
|
|
91
|
-
)
|
|
92
|
-
}
|
|
145
|
+
disabled={projectLockedDestinationChain || projectLockedSourceChain}
|
|
146
|
+
onClick={() => setChainPickerModalOpen(true)}
|
|
147
|
+
className={`${className || ""}`}
|
|
93
148
|
>
|
|
94
149
|
<div className="flex justify-between items-center p-4 gap-8">
|
|
95
150
|
<div className="flex flex-col font-medium items-start">
|
|
@@ -100,7 +155,7 @@ export const ChainPanel = ({ chain, type }: Props) => {
|
|
|
100
155
|
{chain ? chain.displayName : "Select"}
|
|
101
156
|
</p>
|
|
102
157
|
</div>
|
|
103
|
-
{!
|
|
158
|
+
{!projectLockedDestinationChain && !projectLockedSourceChain && (
|
|
104
159
|
<div className="w-4 h-2 fill-t_text_primary">
|
|
105
160
|
<ArrowDownIcon />
|
|
106
161
|
</div>
|
|
@@ -57,11 +57,15 @@ export const TokenItem = ({ token, selectedTokenAddress, onClick }: Props) => {
|
|
|
57
57
|
})
|
|
58
58
|
: "<0.0001"}
|
|
59
59
|
</div>
|
|
60
|
-
) :
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
) : (
|
|
61
|
+
<>
|
|
62
|
+
{address ? (
|
|
63
|
+
<div>
|
|
64
|
+
<Skeleton className="w-[48px] h-[12px]" />
|
|
65
|
+
</div>
|
|
66
|
+
) : null}
|
|
67
|
+
</>
|
|
68
|
+
)}
|
|
65
69
|
</div>
|
|
66
70
|
</div>
|
|
67
71
|
);
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
} from "@src/components";
|
|
11
11
|
import { SwapPanelType } from "@src/components/Swap/SwapView";
|
|
12
12
|
import { useSwapContext } from "@src/context";
|
|
13
|
-
import { useModal } from "@src/context/ModalProvider";
|
|
14
13
|
import { ERC20Abi } from "@src/contracts";
|
|
15
14
|
import { useEvmContractApi } from "@src/hooks";
|
|
16
15
|
import { Chain, Ecosystem, ImportedTokenData, TokenOption } from "@src/models";
|
|
@@ -50,9 +49,9 @@ export const TokenPicker = ({
|
|
|
50
49
|
const currentRouteRequestNonce = useRef<number>(0);
|
|
51
50
|
const tokenSearchRef = useRef<HTMLInputElement | null>(null);
|
|
52
51
|
|
|
53
|
-
const { supportedChains, findTokenDataByAddressAndChain } =
|
|
52
|
+
const { bridgeUI, supportedChains, findTokenDataByAddressAndChain } =
|
|
53
|
+
useSwapContext();
|
|
54
54
|
const evmContractApi = useEvmContractApi();
|
|
55
|
-
const { closeModal } = useModal();
|
|
56
55
|
|
|
57
56
|
useEffect(() => {
|
|
58
57
|
setShowImportWarning(false);
|
|
@@ -133,6 +132,7 @@ export const TokenPicker = ({
|
|
|
133
132
|
|
|
134
133
|
useEffect(() => {
|
|
135
134
|
if (
|
|
135
|
+
!bridgeUI &&
|
|
136
136
|
isETHAddressValid(searchValue) &&
|
|
137
137
|
!findTokenDataByAddressAndChain(searchValue.toLowerCase(), chain.chainId)
|
|
138
138
|
) {
|
|
@@ -141,7 +141,13 @@ export const TokenPicker = ({
|
|
|
141
141
|
setLoadingCustomTokenData(false);
|
|
142
142
|
setCustomTokenData(null);
|
|
143
143
|
}
|
|
144
|
-
}, [
|
|
144
|
+
}, [
|
|
145
|
+
bridgeUI,
|
|
146
|
+
searchValue,
|
|
147
|
+
getCustomTokenData,
|
|
148
|
+
findTokenDataByAddressAndChain,
|
|
149
|
+
chain,
|
|
150
|
+
]);
|
|
145
151
|
|
|
146
152
|
useEffect(() => {
|
|
147
153
|
setSearchValue("");
|
|
@@ -217,7 +223,7 @@ export const TokenPicker = ({
|
|
|
217
223
|
<div className="text-base/4 mb-4">Import token</div>
|
|
218
224
|
<div
|
|
219
225
|
className="w-4 h-4 fill-t_text_primary cursor-pointer"
|
|
220
|
-
onClick={
|
|
226
|
+
onClick={() => setModalOpen(false)}
|
|
221
227
|
>
|
|
222
228
|
<CloseIcon />
|
|
223
229
|
</div>
|
|
@@ -301,7 +307,7 @@ export const TokenPicker = ({
|
|
|
301
307
|
<div className="text-base/4 text-t_text_primary mb-4">{`Pick ${type} token`}</div>
|
|
302
308
|
<div
|
|
303
309
|
className="w-4 h-4 fill-t_text_primary cursor-pointer"
|
|
304
|
-
onClick={
|
|
310
|
+
onClick={() => setModalOpen(false)}
|
|
305
311
|
>
|
|
306
312
|
<CloseIcon />
|
|
307
313
|
</div>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ArrowDownIcon } from "@src/assets/icons";
|
|
2
|
-
import { TokenLogo } from "@src/components";
|
|
2
|
+
import { Modal, TokenLogo } from "@src/components";
|
|
3
3
|
import { useSwapContext } from "@src/context";
|
|
4
|
-
import { useModal } from "@src/context/ModalProvider";
|
|
5
4
|
import { Chain, Token, TokenOption } from "@src/models";
|
|
6
5
|
import { useMemo, useState } from "react";
|
|
7
6
|
import { SwapPanelType } from "../../index";
|
|
@@ -11,12 +10,12 @@ type Props = {
|
|
|
11
10
|
chain: Chain | undefined;
|
|
12
11
|
token: Token | undefined;
|
|
13
12
|
type: SwapPanelType;
|
|
13
|
+
className?: string;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export const TokenPanel = ({ chain, token, type }: Props) => {
|
|
17
|
-
const [open, setOpen] = useState(false);
|
|
18
|
-
|
|
16
|
+
export const TokenPanel = ({ chain, token, type, className }: Props) => {
|
|
19
17
|
const {
|
|
18
|
+
bridgeUI,
|
|
20
19
|
srcChainTokensOptions,
|
|
21
20
|
srcChainOtherTokensOptions,
|
|
22
21
|
dstChainTokensOptions,
|
|
@@ -26,21 +25,32 @@ export const TokenPanel = ({ chain, token, type }: Props) => {
|
|
|
26
25
|
supportedChains,
|
|
27
26
|
setDstToken,
|
|
28
27
|
setDstChain,
|
|
29
|
-
|
|
28
|
+
dstTokenLocked,
|
|
29
|
+
srcTokenLocked,
|
|
30
30
|
} = useSwapContext();
|
|
31
31
|
|
|
32
|
-
const
|
|
33
|
-
() => type === "destination" &&
|
|
34
|
-
[type,
|
|
32
|
+
const integratorLockedDestinationToken = useMemo(
|
|
33
|
+
() => type === "destination" && dstTokenLocked,
|
|
34
|
+
[type, dstTokenLocked],
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const integratorLockedSourceToken = useMemo(
|
|
38
|
+
() => type === "source" && srcTokenLocked,
|
|
39
|
+
[type, srcTokenLocked],
|
|
35
40
|
);
|
|
36
41
|
|
|
37
|
-
const
|
|
42
|
+
const [tokenPickerModalOpen, setTokenPickerModalOpen] = useState(false);
|
|
38
43
|
|
|
39
44
|
const tokensWithBalances = useMemo(
|
|
40
45
|
() => (type === "source" ? srcChainTokensOptions : dstChainTokensOptions),
|
|
41
46
|
[dstChainTokensOptions, srcChainTokensOptions, type],
|
|
42
47
|
);
|
|
43
48
|
|
|
49
|
+
const pickerDisabled = useMemo(
|
|
50
|
+
() => type === "destination" && bridgeUI,
|
|
51
|
+
[bridgeUI, type],
|
|
52
|
+
);
|
|
53
|
+
|
|
44
54
|
const otherTokensWithBalances = useMemo(
|
|
45
55
|
() =>
|
|
46
56
|
type === "source"
|
|
@@ -61,28 +71,37 @@ export const TokenPanel = ({ chain, token, type }: Props) => {
|
|
|
61
71
|
setDstToken(token);
|
|
62
72
|
setDstChain(newChain);
|
|
63
73
|
}
|
|
64
|
-
|
|
74
|
+
setTokenPickerModalOpen(false);
|
|
65
75
|
};
|
|
66
76
|
|
|
67
77
|
return (
|
|
68
78
|
<>
|
|
79
|
+
{tokenPickerModalOpen && (
|
|
80
|
+
<Modal onClose={() => setTokenPickerModalOpen(false)}>
|
|
81
|
+
<TokenPicker
|
|
82
|
+
type={type}
|
|
83
|
+
chain={chain!}
|
|
84
|
+
tokens={tokensWithBalances}
|
|
85
|
+
otherTokens={otherTokensWithBalances}
|
|
86
|
+
selectedTokenAddress={token?.address}
|
|
87
|
+
onSelect={onTokenSelect}
|
|
88
|
+
isOpen={tokenPickerModalOpen}
|
|
89
|
+
setModalOpen={setTokenPickerModalOpen}
|
|
90
|
+
/>
|
|
91
|
+
</Modal>
|
|
92
|
+
)}
|
|
93
|
+
|
|
69
94
|
<button
|
|
70
95
|
type="button"
|
|
71
|
-
disabled={
|
|
96
|
+
disabled={
|
|
97
|
+
pickerDisabled ||
|
|
98
|
+
integratorLockedDestinationToken ||
|
|
99
|
+
integratorLockedSourceToken
|
|
100
|
+
}
|
|
72
101
|
onClick={() => {
|
|
73
|
-
|
|
74
|
-
<TokenPicker
|
|
75
|
-
type={type}
|
|
76
|
-
chain={chain!}
|
|
77
|
-
tokens={tokensWithBalances}
|
|
78
|
-
otherTokens={otherTokensWithBalances}
|
|
79
|
-
selectedTokenAddress={token?.address}
|
|
80
|
-
onSelect={onTokenSelect}
|
|
81
|
-
isOpen={open}
|
|
82
|
-
setModalOpen={setOpen}
|
|
83
|
-
/>,
|
|
84
|
-
);
|
|
102
|
+
setTokenPickerModalOpen(true);
|
|
85
103
|
}}
|
|
104
|
+
className={`${className || ""}`}
|
|
86
105
|
>
|
|
87
106
|
<div className="flex justify-between items-center p-4 gap-8 border-r border-solid border-t_text_primary border-opacity-10">
|
|
88
107
|
<div className="flex gap-2 items-center">
|
|
@@ -98,11 +117,13 @@ export const TokenPanel = ({ chain, token, type }: Props) => {
|
|
|
98
117
|
</p>
|
|
99
118
|
</div>
|
|
100
119
|
</div>
|
|
101
|
-
{!
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
120
|
+
{!pickerDisabled &&
|
|
121
|
+
!integratorLockedDestinationToken &&
|
|
122
|
+
!integratorLockedSourceToken && (
|
|
123
|
+
<div className="w-4 h-2 fill-t_text_primary">
|
|
124
|
+
<ArrowDownIcon />
|
|
125
|
+
</div>
|
|
126
|
+
)}
|
|
106
127
|
</div>
|
|
107
128
|
</button>
|
|
108
129
|
</>
|
|
@@ -24,9 +24,14 @@ export const SwapPanel = ({ type }: Props) => {
|
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<div className="flex flex-col x-border rounded-xl bg-t_bg_tertiary bg-opacity-5">
|
|
27
|
-
<div className="
|
|
28
|
-
<TokenPanel
|
|
29
|
-
|
|
27
|
+
<div className="flex border-b border-solid border-t_text_primary border-opacity-10">
|
|
28
|
+
<TokenPanel
|
|
29
|
+
chain={chain}
|
|
30
|
+
token={token}
|
|
31
|
+
type={type}
|
|
32
|
+
className="w-full flex-grow"
|
|
33
|
+
/>
|
|
34
|
+
<ChainPanel chain={chain} type={type} className="w-full max-w-[36%]" />
|
|
30
35
|
</div>
|
|
31
36
|
<div
|
|
32
37
|
className={`flex justify-between ${
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { CloseIcon, WalletConnectIcon } from "@src/assets/icons";
|
|
2
|
-
import { useModal } from "@src/context/ModalProvider";
|
|
3
2
|
import { FC, useCallback, useMemo } from "react";
|
|
4
3
|
import { Connector, useConnect } from "wagmi";
|
|
5
4
|
|
|
@@ -27,8 +26,10 @@ const ConnectorIcon: FC<{ connector: Connector; className?: string }> = ({
|
|
|
27
26
|
}
|
|
28
27
|
};
|
|
29
28
|
|
|
30
|
-
export const WalletPicker: FC<{ className?: string
|
|
31
|
-
|
|
29
|
+
export const WalletPicker: FC<{ className?: string; onClose: () => void }> = ({
|
|
30
|
+
className,
|
|
31
|
+
onClose,
|
|
32
|
+
}) => {
|
|
32
33
|
const { connectors, connectAsync } = useConnect();
|
|
33
34
|
|
|
34
35
|
const allowedConnectors = useMemo(() => {
|
|
@@ -44,9 +45,9 @@ export const WalletPicker: FC<{ className?: string }> = ({ className }) => {
|
|
|
44
45
|
const handleWalletClick = useCallback(
|
|
45
46
|
async (connector: Connector) => {
|
|
46
47
|
await connectAsync({ connector });
|
|
47
|
-
|
|
48
|
+
onClose();
|
|
48
49
|
},
|
|
49
|
-
[connectAsync,
|
|
50
|
+
[connectAsync, onClose],
|
|
50
51
|
);
|
|
51
52
|
|
|
52
53
|
return (
|
|
@@ -55,7 +56,7 @@ export const WalletPicker: FC<{ className?: string }> = ({ className }) => {
|
|
|
55
56
|
<div className="text-base/4 mb-4 text-t_text_primary">Pick wallet</div>
|
|
56
57
|
<div
|
|
57
58
|
className="w-4 h-4 fill-t_text_primary cursor-pointer"
|
|
58
|
-
onClick={
|
|
59
|
+
onClick={onClose}
|
|
59
60
|
>
|
|
60
61
|
<CloseIcon />
|
|
61
62
|
</div>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import { ReorderButton } from "../ReorderButton/ReorderButton";
|
|
1
2
|
import { FeesPanel } from "./FeesPanel";
|
|
2
3
|
import { SwapButton } from "./SwapButton";
|
|
3
4
|
import { SwapPanel } from "./SwapPanel";
|
|
4
|
-
import { ArrowIcon } from "@src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon";
|
|
5
5
|
|
|
6
6
|
export type SwapPanelType = "source" | "destination";
|
|
7
7
|
|
|
8
8
|
export const SwapView = () => {
|
|
9
9
|
return (
|
|
10
10
|
<div className="flex flex-col gap-2 fill-t_text_primary">
|
|
11
|
-
<div className="
|
|
11
|
+
<div className="flex flex-col gap-5">
|
|
12
12
|
<SwapPanel type="source" />
|
|
13
|
-
<
|
|
13
|
+
<ReorderButton />
|
|
14
14
|
<SwapPanel type="destination" />
|
|
15
15
|
</div>
|
|
16
16
|
<FeesPanel />
|
|
@@ -25,7 +25,7 @@ export const Swap = ({ onClose }: Props) => {
|
|
|
25
25
|
|
|
26
26
|
return (
|
|
27
27
|
<div
|
|
28
|
-
className={`flex flex-col gap-5 p-4
|
|
28
|
+
className={`relative flex flex-col gap-5 p-4 text-t_text_primary bg-t_bg_primary rounded-3xl flex-1`}
|
|
29
29
|
>
|
|
30
30
|
<Header onClose={onClose} />
|
|
31
31
|
{view}
|
|
@@ -5,14 +5,14 @@ import {
|
|
|
5
5
|
SwapProvider,
|
|
6
6
|
TransactionProvider,
|
|
7
7
|
TxUIWrapper,
|
|
8
|
+
useHistory,
|
|
8
9
|
} from "@src/context";
|
|
9
|
-
import { ModalProvider } from "@src/context/ModalProvider";
|
|
10
10
|
import { Chain, ModalIntegrationPayload, Route } from "@src/models";
|
|
11
11
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
12
12
|
import { FC, MouseEvent, useEffect, useMemo } from "react";
|
|
13
|
+
import { ErrorBoundary } from "react-error-boundary";
|
|
13
14
|
import { useReconnect, WagmiProvider } from "wagmi";
|
|
14
15
|
import { changeHostVariableColor } from "../../../localTheme";
|
|
15
|
-
import { ErrorBoundary } from "react-error-boundary";
|
|
16
16
|
|
|
17
17
|
export type TxConfigFormPayload = Omit<
|
|
18
18
|
ModalIntegrationPayload,
|
|
@@ -24,7 +24,6 @@ export type TxConfigFormPayload = Omit<
|
|
|
24
24
|
srcTokenAddr?: string;
|
|
25
25
|
dstDisplayTokenAddr?: string;
|
|
26
26
|
supportedChains: Chain[];
|
|
27
|
-
defaultWalletPicker?: boolean;
|
|
28
27
|
};
|
|
29
28
|
|
|
30
29
|
const queryClient = new QueryClient();
|
|
@@ -45,6 +44,27 @@ const WagmiReload: FC = () => {
|
|
|
45
44
|
return <></>;
|
|
46
45
|
};
|
|
47
46
|
|
|
47
|
+
const PendingTransactionsEmitter: FC<{
|
|
48
|
+
onPendingTransactionsChange: ModalIntegrationPayload["onPendingTransactionsChange"];
|
|
49
|
+
}> = ({ onPendingTransactionsChange }) => {
|
|
50
|
+
const { history } = useHistory();
|
|
51
|
+
|
|
52
|
+
const pendingTransactions = useMemo(
|
|
53
|
+
() => history.filter((entry) => entry.status === "IN_PROGRESS"),
|
|
54
|
+
[history],
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (onPendingTransactionsChange) {
|
|
59
|
+
onPendingTransactionsChange(pendingTransactions);
|
|
60
|
+
} else if (window.xPayOnPendingTransactionsChange) {
|
|
61
|
+
window.xPayOnPendingTransactionsChange(pendingTransactions);
|
|
62
|
+
}
|
|
63
|
+
}, [onPendingTransactionsChange, pendingTransactions]);
|
|
64
|
+
|
|
65
|
+
return <></>;
|
|
66
|
+
};
|
|
67
|
+
|
|
48
68
|
export const TxConfigForm = ({
|
|
49
69
|
integratorId,
|
|
50
70
|
dstChainId,
|
|
@@ -61,6 +81,16 @@ export const TxConfigForm = ({
|
|
|
61
81
|
lightTheme,
|
|
62
82
|
defaultWalletPicker,
|
|
63
83
|
styles,
|
|
84
|
+
onPendingTransactionsChange,
|
|
85
|
+
dstTokenLocked,
|
|
86
|
+
dstChainLocked,
|
|
87
|
+
srcTokenLocked,
|
|
88
|
+
srcChainLocked,
|
|
89
|
+
onDstTokenChange,
|
|
90
|
+
onDstChainChange,
|
|
91
|
+
onSrcTokenChange,
|
|
92
|
+
onSrcChainChange,
|
|
93
|
+
bridge,
|
|
64
94
|
}: TxConfigFormPayload &
|
|
65
95
|
(
|
|
66
96
|
| {
|
|
@@ -103,6 +133,9 @@ export const TxConfigForm = ({
|
|
|
103
133
|
<QueryClientProvider client={queryClient}>
|
|
104
134
|
<WagmiReload />
|
|
105
135
|
<HistoryProvider>
|
|
136
|
+
<PendingTransactionsEmitter
|
|
137
|
+
onPendingTransactionsChange={onPendingTransactionsChange}
|
|
138
|
+
/>
|
|
106
139
|
<SwapProvider
|
|
107
140
|
integrationConfig={{
|
|
108
141
|
integratorId,
|
|
@@ -114,6 +147,15 @@ export const TxConfigForm = ({
|
|
|
114
147
|
desc,
|
|
115
148
|
dstDisplayTokenAddr,
|
|
116
149
|
defaultWalletPicker,
|
|
150
|
+
dstTokenLocked,
|
|
151
|
+
dstChainLocked,
|
|
152
|
+
srcTokenLocked,
|
|
153
|
+
srcChainLocked,
|
|
154
|
+
onDstTokenChange,
|
|
155
|
+
onDstChainChange,
|
|
156
|
+
onSrcTokenChange,
|
|
157
|
+
onSrcChainChange,
|
|
158
|
+
bridge,
|
|
117
159
|
}}
|
|
118
160
|
supportedChains={supportedChains}
|
|
119
161
|
wagmiConfig={wagmiConfig}
|
|
@@ -121,24 +163,22 @@ export const TxConfigForm = ({
|
|
|
121
163
|
>
|
|
122
164
|
<TransactionProvider>
|
|
123
165
|
<TxUIWrapper>
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
>
|
|
130
|
-
<
|
|
131
|
-
<Swap onSubmit={onSubmit} onClose={onClose} />
|
|
132
|
-
<PoweredBy />
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
) : (
|
|
136
|
-
<div className="bg-t_bg_primary rounded-3xl overflow-auto text-t_text_primary border-2 border-solid border-[rgba(255,255,255,0.1)] min-h-[432px] w-full">
|
|
137
|
-
<Swap onSubmit={() => {}} onClose={() => {}} />
|
|
166
|
+
{overlay ? (
|
|
167
|
+
<div
|
|
168
|
+
className="top-0 left-0 right-0 bottom-0 bg-[rgba(0,0,0,0.8)] fixed flex flex-col items-center justify-center z-10"
|
|
169
|
+
onMouseDown={onBackdropClick}
|
|
170
|
+
>
|
|
171
|
+
<div className="relative bg-t_bg_primary rounded-3xl overflow-auto text-t_text_primary border-2 border-solid border-[rgba(255,255,255,0.1)] min-w-x_modal max-w-x_modal min-h-[532px] w-full">
|
|
172
|
+
<Swap onSubmit={onSubmit} onClose={onClose} />
|
|
138
173
|
<PoweredBy />
|
|
139
174
|
</div>
|
|
140
|
-
|
|
141
|
-
|
|
175
|
+
</div>
|
|
176
|
+
) : (
|
|
177
|
+
<div className="bg-t_bg_primary rounded-3xl overflow-auto text-t_text_primary border-2 border-solid border-[rgba(255,255,255,0.1)] min-h-[532px] w-full flex flex-col">
|
|
178
|
+
<Swap onSubmit={() => {}} onClose={() => {}} />
|
|
179
|
+
<PoweredBy />
|
|
180
|
+
</div>
|
|
181
|
+
)}
|
|
142
182
|
</TxUIWrapper>
|
|
143
183
|
</TransactionProvider>
|
|
144
184
|
</SwapProvider>
|
|
@@ -162,6 +202,11 @@ export const openTxConfigForm = async ({
|
|
|
162
202
|
lightTheme,
|
|
163
203
|
defaultWalletPicker,
|
|
164
204
|
styles,
|
|
205
|
+
onPendingTransactionsChange,
|
|
206
|
+
dstTokenLocked,
|
|
207
|
+
dstChainLocked,
|
|
208
|
+
srcTokenLocked,
|
|
209
|
+
srcChainLocked,
|
|
165
210
|
}: TxConfigFormPayload): Promise<Route> => {
|
|
166
211
|
try {
|
|
167
212
|
if (xpayRoot === null) {
|
|
@@ -200,6 +245,11 @@ export const openTxConfigForm = async ({
|
|
|
200
245
|
}}
|
|
201
246
|
overlay={true}
|
|
202
247
|
defaultWalletPicker={defaultWalletPicker}
|
|
248
|
+
onPendingTransactionsChange={onPendingTransactionsChange}
|
|
249
|
+
dstTokenLocked={dstTokenLocked}
|
|
250
|
+
dstChainLocked={dstChainLocked}
|
|
251
|
+
srcTokenLocked={srcTokenLocked}
|
|
252
|
+
srcChainLocked={srcChainLocked}
|
|
203
253
|
/>,
|
|
204
254
|
);
|
|
205
255
|
});
|