@xswap-link/sdk 0.2.5 → 0.3.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/.github/workflows/main.yml +2 -2
- package/.github/workflows/publish.yml +2 -2
- package/CHANGELOG.md +12 -0
- package/dist/index.css +325 -257
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1296 -516
- package/dist/index.mjs +1323 -537
- package/package.json +1 -1
- package/src/components/Alert/index.tsx +1 -1
- package/src/components/Skeleton/index.tsx +3 -1
- package/src/components/Spinner/index.tsx +28 -0
- package/src/components/TxConfigForm/BalanceComponent.tsx +1 -1
- package/src/components/TxConfigForm/Button.tsx +1 -1
- package/src/components/TxConfigForm/ChainListElement.tsx +2 -2
- package/src/components/TxConfigForm/ConfirmationAmount.tsx +91 -0
- package/src/components/TxConfigForm/Description.tsx +5 -3
- package/src/components/TxConfigForm/ErrorField.tsx +4 -2
- package/src/components/TxConfigForm/FeesDetails.tsx +25 -31
- package/src/components/TxConfigForm/Form.tsx +763 -118
- package/src/components/TxConfigForm/History.tsx +5 -5
- package/src/components/TxConfigForm/HistoryCard.tsx +33 -40
- package/src/components/TxConfigForm/PoweredBy.tsx +2 -2
- package/src/components/TxConfigForm/Settings.tsx +33 -27
- package/src/components/TxConfigForm/Summary.tsx +33 -31
- package/src/components/TxConfigForm/SwapPanel.tsx +12 -15
- package/src/components/TxConfigForm/TokenPicker.tsx +36 -34
- package/src/components/TxConfigForm/TopBar.tsx +8 -8
- package/src/components/TxConfigForm/UsdPrice.tsx +4 -14
- package/src/components/TxConfigForm/index.tsx +37 -10
- package/src/components/TxStatusButton/index.tsx +42 -28
- package/src/components/UnknownTokenLogo/UnknownTokenLogo.tsx +1 -1
- package/src/components/global.css +7 -5
- package/src/components/icons/CircularProgressIcon.tsx +1 -1
- package/src/components/icons/ErrorIcon.tsx +32 -0
- package/src/components/icons/SignIcon.tsx +17 -0
- package/src/components/icons/SuccessIcon.tsx +29 -0
- package/src/components/icons/index.ts +3 -0
- package/src/config/init.tsx +42 -24
- package/src/constants/index.ts +2 -2
- package/src/models/payloads/GetSwapTxPayload.ts +2 -0
- package/src/services/integrations/monitoring.ts +10 -3
- package/src/services/integrations/transactions.ts +9 -3
- package/src/utils/contracts.ts +18 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/parseWeb3Error.ts +93 -0
- package/tailwind.config.js +40 -0
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import "@src/global.css";
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
FormEvent,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from "react";
|
|
3
10
|
import { ethers } from "ethers";
|
|
4
|
-
import { useAccount, useSwitchChain } from "wagmi";
|
|
11
|
+
import { Config, useAccount, useSendTransaction, useSwitchChain } from "wagmi";
|
|
5
12
|
import { Chain, Route, Token, TokenBalances, TokenPrices } from "@src/models";
|
|
6
13
|
import { getCustomTokenData, getPrices, getRoute } from "@src/services";
|
|
7
|
-
import {
|
|
8
|
-
|
|
14
|
+
import {
|
|
15
|
+
getAllowanceOf,
|
|
16
|
+
getBalances,
|
|
17
|
+
parseWeb3Error,
|
|
18
|
+
safeBigNumberFrom,
|
|
19
|
+
weiToHumanReadable,
|
|
20
|
+
} from "@src/utils";
|
|
21
|
+
import { CCIP_EXPLORER, ROUTE_TIMEOUT_MS } from "@src/constants";
|
|
9
22
|
import { TxConfigFormProps } from "@src/components";
|
|
10
23
|
import { useDebounce } from "@src/hooks";
|
|
11
24
|
import { ADDRESSES } from "@src/contracts";
|
|
@@ -19,6 +32,21 @@ import { ErrorField } from "./ErrorField";
|
|
|
19
32
|
import { Description } from "./Description";
|
|
20
33
|
import { DEFAULT_SOURCE_CHAIN_ID } from "@src/constants";
|
|
21
34
|
import { Button } from "./Button";
|
|
35
|
+
import { getChainId, waitForTransactionReceipt } from "wagmi/actions";
|
|
36
|
+
import { renderTxStatus } from "@src/services";
|
|
37
|
+
import { ConfirmationAmount } from "./ConfirmationAmount";
|
|
38
|
+
import {
|
|
39
|
+
ArrowDownIcon,
|
|
40
|
+
ArrowRightIcon,
|
|
41
|
+
ArrowUpRightIcon,
|
|
42
|
+
CheckIcon,
|
|
43
|
+
CloseIcon,
|
|
44
|
+
ErrorIcon,
|
|
45
|
+
SignIcon,
|
|
46
|
+
SuccessIcon,
|
|
47
|
+
} from "../icons";
|
|
48
|
+
import { Spinner } from "../Spinner";
|
|
49
|
+
import { UnknownTokenLogo } from "../UnknownTokenLogo/UnknownTokenLogo";
|
|
22
50
|
|
|
23
51
|
export const Form = ({
|
|
24
52
|
integratorId,
|
|
@@ -27,15 +55,23 @@ export const Form = ({
|
|
|
27
55
|
customContractCalls,
|
|
28
56
|
desc,
|
|
29
57
|
supportedChains,
|
|
58
|
+
retrunTransactions,
|
|
59
|
+
dstDisplayTokenAddr,
|
|
60
|
+
wagmiConfig,
|
|
30
61
|
onSubmit,
|
|
31
62
|
onClose,
|
|
63
|
+
setBackdropClickDisabled,
|
|
32
64
|
}: TxConfigFormProps & {
|
|
65
|
+
wagmiConfig: Config;
|
|
66
|
+
retrunTransactions: boolean;
|
|
33
67
|
onSubmit: (route: Route) => void;
|
|
34
68
|
onClose: () => void;
|
|
69
|
+
setBackdropClickDisabled: (disabled: boolean) => void;
|
|
35
70
|
}) => {
|
|
36
71
|
const [signer, setSigner] = useState<string | undefined>();
|
|
37
72
|
const [dstChain, setDstChain] = useState<Chain>();
|
|
38
73
|
const [dstToken, setDstToken] = useState<Token>();
|
|
74
|
+
const [dstDisplayToken, setDstDisplayToken] = useState<Token>();
|
|
39
75
|
const [srcChain, setSrcChain] = useState<Chain>();
|
|
40
76
|
const [srcToken, setSrcToken] = useState<Token>();
|
|
41
77
|
const [amount, setAmount] = useState<string>("");
|
|
@@ -50,17 +86,43 @@ export const Form = ({
|
|
|
50
86
|
const [formError, setFormError] = useState("");
|
|
51
87
|
const [slippage, setSlippage] = useState<string>("1.5");
|
|
52
88
|
const [feesDetailsShown, setFeesDetailsShown] = useState(false);
|
|
53
|
-
const [
|
|
54
|
-
|
|
89
|
+
const [executingTransactions, setExecutingTransactions] = useState(false);
|
|
90
|
+
const [transactionSuccessHash, setTransactionSuccessHash] = useState<
|
|
91
|
+
string | undefined
|
|
92
|
+
>();
|
|
93
|
+
|
|
94
|
+
const [txLoading, setTxLoading] = useState(false);
|
|
95
|
+
const [approveTxLoading, setApproveTxLoading] = useState(false);
|
|
96
|
+
const [approveTxDone, setApproveTxDone] = useState(false);
|
|
97
|
+
const [transactionError, setTransactionError] = useState<string | null>(null);
|
|
98
|
+
const currentRouteRequestNonce = useRef<number>(0);
|
|
99
|
+
|
|
100
|
+
// Allowance section
|
|
101
|
+
const prevAllowanceValuesRef = useRef({
|
|
102
|
+
srcChainId: srcChain?.chainId,
|
|
103
|
+
srcTokenAddress: srcToken?.address,
|
|
104
|
+
routeTo: ethers.constants.AddressZero,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const currentAllowanceRequestNonce = useRef<number>(0);
|
|
108
|
+
|
|
109
|
+
const [isAllowanceLoading, setIsAllowanceLoading] = useState(false);
|
|
110
|
+
const [srcTokenAllowance, setSrcTokenAllowance] = useState("0");
|
|
111
|
+
// End of Allowance section
|
|
112
|
+
|
|
113
|
+
// Wagmi hook to execute transactions
|
|
114
|
+
const { sendTransaction } = useSendTransaction({ config: wagmiConfig });
|
|
55
115
|
|
|
56
116
|
const debouncedAmount = useDebounce(amount, 1000);
|
|
57
117
|
const account = useAccount();
|
|
58
118
|
const { switchChainAsync } = useSwitchChain();
|
|
59
119
|
|
|
120
|
+
// set signer address
|
|
60
121
|
useEffect(() => {
|
|
61
122
|
setSigner(account.address);
|
|
62
123
|
}, [account.address]);
|
|
63
124
|
|
|
125
|
+
// set source chain
|
|
64
126
|
useEffect(() => {
|
|
65
127
|
const defaultChain = supportedChains.find(
|
|
66
128
|
({ chainId }) => chainId === account.chainId?.toString(),
|
|
@@ -73,10 +135,12 @@ export const Form = ({
|
|
|
73
135
|
);
|
|
74
136
|
}, [account.chainId]);
|
|
75
137
|
|
|
138
|
+
// set destination chain
|
|
76
139
|
useEffect(() => {
|
|
77
140
|
setDstChain(supportedChains.find((chain) => chain.chainId === dstChainId));
|
|
78
141
|
}, [supportedChains, dstChainId]);
|
|
79
142
|
|
|
143
|
+
// set destination token
|
|
80
144
|
useEffect(() => {
|
|
81
145
|
(async () => {
|
|
82
146
|
if (!dstChain) {
|
|
@@ -95,57 +159,85 @@ export const Form = ({
|
|
|
95
159
|
}
|
|
96
160
|
|
|
97
161
|
setDstToken(dstTokenResult);
|
|
162
|
+
|
|
163
|
+
if (dstDisplayTokenAddr) {
|
|
164
|
+
let dstDisplayTokenResult = dstChain?.tokens.find(
|
|
165
|
+
(token) =>
|
|
166
|
+
token.address.toLowerCase() === dstDisplayTokenAddr.toLowerCase(),
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
if (!dstDisplayTokenResult) {
|
|
170
|
+
dstDisplayTokenResult = await getCustomTokenData(
|
|
171
|
+
dstChain,
|
|
172
|
+
dstDisplayTokenAddr.toLowerCase(),
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
setDstDisplayToken(dstDisplayTokenResult);
|
|
177
|
+
}
|
|
98
178
|
})();
|
|
99
179
|
}, [dstChain]);
|
|
100
180
|
|
|
181
|
+
// Handle fetching route
|
|
101
182
|
useEffect(() => {
|
|
102
183
|
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
184
|
+
!(
|
|
185
|
+
integratorId &&
|
|
186
|
+
srcChain &&
|
|
187
|
+
srcToken &&
|
|
188
|
+
dstChain &&
|
|
189
|
+
debouncedAmount &&
|
|
190
|
+
paymentToken &&
|
|
191
|
+
signer &&
|
|
192
|
+
slippage
|
|
193
|
+
)
|
|
110
194
|
) {
|
|
111
|
-
|
|
112
|
-
const timeout = setTimeout(() => {
|
|
113
|
-
setFormError("Getting Route is taking longer than usually");
|
|
114
|
-
}, ROUTE_TIMEOUT_MS);
|
|
115
|
-
setIsGettingRoute(true);
|
|
116
|
-
setFeesDetailsShown(false);
|
|
117
|
-
if (!srcToken.decimals)
|
|
118
|
-
throw new Error(
|
|
119
|
-
`Configuration error: selected token ($${srcToken.symbol} ${srcToken.name}) has unknown decimals param.`,
|
|
120
|
-
);
|
|
121
|
-
getRoute({
|
|
122
|
-
integratorId,
|
|
123
|
-
fromAmount: ethers.utils
|
|
124
|
-
.parseUnits(debouncedAmount, srcToken.decimals)
|
|
125
|
-
.toString(),
|
|
126
|
-
fromAddress: signer || ADDRESSES[srcChain.chainId]!.FeeCollector,
|
|
127
|
-
fromChain: srcChain.chainId,
|
|
128
|
-
fromToken: srcToken.address,
|
|
129
|
-
toAddress: signer || ADDRESSES[dstChain.chainId]!.FeeCollector,
|
|
130
|
-
toChain: dstChainId,
|
|
131
|
-
toToken: dstTokenAddr,
|
|
132
|
-
paymentToken: paymentToken.address,
|
|
133
|
-
slippage: Number(slippage),
|
|
134
|
-
expressDelivery: expressChecked && !exceedsExpressDeliveryLimit,
|
|
135
|
-
customContractCalls,
|
|
136
|
-
})
|
|
137
|
-
.then((response) => {
|
|
138
|
-
setRoute(response);
|
|
139
|
-
setFormError("");
|
|
140
|
-
})
|
|
141
|
-
.catch((err) => {
|
|
142
|
-
setFormError(err.message);
|
|
143
|
-
})
|
|
144
|
-
.finally(() => {
|
|
145
|
-
setIsGettingRoute(false);
|
|
146
|
-
clearTimeout(timeout);
|
|
147
|
-
});
|
|
195
|
+
return;
|
|
148
196
|
}
|
|
197
|
+
|
|
198
|
+
setFormError("");
|
|
199
|
+
const timeout = setTimeout(() => {
|
|
200
|
+
setFormError("Getting Route is taking longer than usually");
|
|
201
|
+
}, ROUTE_TIMEOUT_MS);
|
|
202
|
+
setIsGettingRoute(true);
|
|
203
|
+
setFeesDetailsShown(false);
|
|
204
|
+
if (!srcToken.decimals)
|
|
205
|
+
throw new Error(
|
|
206
|
+
`Configuration error: selected token ($${srcToken.symbol} ${srcToken.name}) has unknown decimals param.`,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const nonce = Date.now();
|
|
210
|
+
currentRouteRequestNonce.current = nonce;
|
|
211
|
+
getRoute({
|
|
212
|
+
integratorId,
|
|
213
|
+
fromAmount: ethers.utils
|
|
214
|
+
.parseUnits(debouncedAmount, srcToken.decimals)
|
|
215
|
+
.toString(),
|
|
216
|
+
fromAddress: signer || ADDRESSES[srcChain.chainId]!.FeeCollector,
|
|
217
|
+
fromChain: srcChain.chainId,
|
|
218
|
+
fromToken: srcToken.address,
|
|
219
|
+
toAddress: signer || ADDRESSES[dstChain.chainId]!.FeeCollector,
|
|
220
|
+
toChain: dstChainId,
|
|
221
|
+
toToken: dstTokenAddr,
|
|
222
|
+
paymentToken: paymentToken.address,
|
|
223
|
+
slippage: Number(slippage),
|
|
224
|
+
expressDelivery: expressChecked,
|
|
225
|
+
customContractCalls,
|
|
226
|
+
})
|
|
227
|
+
.then((response) => {
|
|
228
|
+
if (nonce !== currentRouteRequestNonce.current) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
setRoute(response);
|
|
232
|
+
setFormError("");
|
|
233
|
+
})
|
|
234
|
+
.catch((err) => {
|
|
235
|
+
setFormError(err.message);
|
|
236
|
+
})
|
|
237
|
+
.finally(() => {
|
|
238
|
+
setIsGettingRoute(false);
|
|
239
|
+
clearTimeout(timeout);
|
|
240
|
+
});
|
|
149
241
|
}, [
|
|
150
242
|
signer,
|
|
151
243
|
srcChain,
|
|
@@ -156,6 +248,58 @@ export const Form = ({
|
|
|
156
248
|
expressChecked,
|
|
157
249
|
]);
|
|
158
250
|
|
|
251
|
+
// Handle fetching allowance
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
(async () => {
|
|
254
|
+
if (
|
|
255
|
+
!signer ||
|
|
256
|
+
!srcToken?.address ||
|
|
257
|
+
!srcChain?.publicRpcUrls[0] ||
|
|
258
|
+
srcToken?.address === ethers.constants.AddressZero
|
|
259
|
+
) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (route && route.transactions.swap?.to) {
|
|
263
|
+
const {
|
|
264
|
+
srcChainId: prevFromChainId,
|
|
265
|
+
srcTokenAddress: prevFromTokenAddress,
|
|
266
|
+
routeTo: prevRouteTo,
|
|
267
|
+
} = prevAllowanceValuesRef.current;
|
|
268
|
+
|
|
269
|
+
const hasChanges =
|
|
270
|
+
srcChain?.chainId !== prevFromChainId ||
|
|
271
|
+
srcToken?.address !== prevFromTokenAddress ||
|
|
272
|
+
route.transactions.swap?.to !== prevRouteTo;
|
|
273
|
+
|
|
274
|
+
if (!hasChanges) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
prevAllowanceValuesRef.current = {
|
|
279
|
+
srcChainId: srcChain?.chainId,
|
|
280
|
+
srcTokenAddress: srcToken?.address,
|
|
281
|
+
routeTo: route.transactions.swap?.to,
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const nonce = Date.now();
|
|
285
|
+
currentAllowanceRequestNonce.current = nonce;
|
|
286
|
+
setIsAllowanceLoading(true);
|
|
287
|
+
const allowanceResponse = await getAllowanceOf(
|
|
288
|
+
srcToken?.address,
|
|
289
|
+
signer,
|
|
290
|
+
route.transactions.swap.to,
|
|
291
|
+
srcChain?.publicRpcUrls[0],
|
|
292
|
+
);
|
|
293
|
+
if (nonce !== currentAllowanceRequestNonce.current) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
setSrcTokenAllowance(allowanceResponse);
|
|
297
|
+
setIsAllowanceLoading(false);
|
|
298
|
+
}
|
|
299
|
+
})();
|
|
300
|
+
}, [srcChain, srcToken?.address, signer, setSrcTokenAllowance, route]);
|
|
301
|
+
|
|
302
|
+
// Set fee payment token
|
|
159
303
|
useEffect(() => {
|
|
160
304
|
if (srcChain) {
|
|
161
305
|
setPaymentToken(
|
|
@@ -168,15 +312,27 @@ export const Form = ({
|
|
|
168
312
|
}
|
|
169
313
|
}, [srcChain]);
|
|
170
314
|
|
|
315
|
+
// Clear state on source token change
|
|
171
316
|
useEffect(() => {
|
|
172
317
|
setAmount("");
|
|
173
318
|
setFormError("");
|
|
319
|
+
setIsGettingRoute(false);
|
|
320
|
+
setRoute(undefined);
|
|
321
|
+
const nonce = Date.now();
|
|
322
|
+
currentRouteRequestNonce.current = nonce;
|
|
174
323
|
}, [srcToken]);
|
|
175
324
|
|
|
325
|
+
// Clear state on source chain change
|
|
176
326
|
useEffect(() => {
|
|
177
327
|
setSrcToken(srcChain?.tokens[0]);
|
|
328
|
+
setAmount("");
|
|
329
|
+
setIsGettingRoute(false);
|
|
330
|
+
setRoute(undefined);
|
|
331
|
+
const nonce = Date.now();
|
|
332
|
+
currentRouteRequestNonce.current = nonce;
|
|
178
333
|
}, [srcChain]);
|
|
179
334
|
|
|
335
|
+
// Fetch token prices on source chain
|
|
180
336
|
useEffect(() => {
|
|
181
337
|
if (srcChain) {
|
|
182
338
|
getPrices({ chainId: srcChain.chainId, currency: "USD" }).then((prices) =>
|
|
@@ -185,94 +341,583 @@ export const Form = ({
|
|
|
185
341
|
}
|
|
186
342
|
}, [srcChain]);
|
|
187
343
|
|
|
344
|
+
// Fetch token balances on source chain
|
|
188
345
|
useEffect(() => {
|
|
189
346
|
if (srcChain && signer) {
|
|
190
347
|
getBalances(srcChain, signer).then((balances) => setBalances(balances));
|
|
191
348
|
}
|
|
192
349
|
}, [srcChain, signer]);
|
|
193
350
|
|
|
351
|
+
// Disable backdrop clicks when executing transactions
|
|
352
|
+
useEffect(() => {
|
|
353
|
+
setBackdropClickDisabled(executingTransactions);
|
|
354
|
+
}, [executingTransactions]);
|
|
355
|
+
|
|
356
|
+
// Check if the allowance needs to be adjusted
|
|
357
|
+
const isAllowanceOk = useMemo(() => {
|
|
358
|
+
return (
|
|
359
|
+
srcToken?.address === ethers.constants.AddressZero ||
|
|
360
|
+
Number(srcTokenAllowance) >= Number(amount)
|
|
361
|
+
);
|
|
362
|
+
}, [srcToken, amount, srcTokenAllowance]);
|
|
363
|
+
|
|
364
|
+
// Execute the transactions recieved from the xPay.
|
|
365
|
+
const triggerTx = useCallback(async () => {
|
|
366
|
+
if (!route) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
setExecutingTransactions(true);
|
|
370
|
+
setBackdropClickDisabled(true);
|
|
371
|
+
setTransactionError(null);
|
|
372
|
+
|
|
373
|
+
// Optional approve for ERC20 tokens.
|
|
374
|
+
if (route.transactions.approve && !isAllowanceOk) {
|
|
375
|
+
setApproveTxDone(false);
|
|
376
|
+
|
|
377
|
+
const { to, data } = route.transactions.approve;
|
|
378
|
+
await sendTransaction(
|
|
379
|
+
{
|
|
380
|
+
to,
|
|
381
|
+
data,
|
|
382
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
383
|
+
} as any,
|
|
384
|
+
{
|
|
385
|
+
onSuccess: async (hash) => {
|
|
386
|
+
setApproveTxLoading(true);
|
|
387
|
+
const chainId = getChainId(wagmiConfig);
|
|
388
|
+
await waitForTransactionReceipt(wagmiConfig, {
|
|
389
|
+
chainId,
|
|
390
|
+
hash,
|
|
391
|
+
});
|
|
392
|
+
setApproveTxLoading(false);
|
|
393
|
+
setApproveTxDone(true);
|
|
394
|
+
swap(route);
|
|
395
|
+
},
|
|
396
|
+
onError: (error) => {
|
|
397
|
+
setTransactionError(`Approval failed: ${error.message}`);
|
|
398
|
+
setApproveTxLoading(false);
|
|
399
|
+
setBackdropClickDisabled(false);
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
);
|
|
403
|
+
} else {
|
|
404
|
+
await swap(route);
|
|
405
|
+
}
|
|
406
|
+
}, [
|
|
407
|
+
route,
|
|
408
|
+
signer,
|
|
409
|
+
srcChain,
|
|
410
|
+
srcToken,
|
|
411
|
+
debouncedAmount,
|
|
412
|
+
paymentToken,
|
|
413
|
+
slippage,
|
|
414
|
+
expressChecked,
|
|
415
|
+
amount,
|
|
416
|
+
srcTokenAllowance,
|
|
417
|
+
]);
|
|
418
|
+
|
|
419
|
+
// Sign and send the swap transaction
|
|
420
|
+
const swap = useCallback(
|
|
421
|
+
async (route: Route) => {
|
|
422
|
+
const { to, value, data } = route.transactions.swap;
|
|
423
|
+
await sendTransaction(
|
|
424
|
+
{
|
|
425
|
+
to,
|
|
426
|
+
value: BigInt(value),
|
|
427
|
+
data,
|
|
428
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
429
|
+
} as any,
|
|
430
|
+
{
|
|
431
|
+
onSuccess: async (hash) => {
|
|
432
|
+
setTxLoading(true);
|
|
433
|
+
// Open the transaction monitor popup to inform user about the tx status
|
|
434
|
+
const chainId = getChainId(wagmiConfig);
|
|
435
|
+
await waitForTransactionReceipt(wagmiConfig, {
|
|
436
|
+
chainId,
|
|
437
|
+
hash,
|
|
438
|
+
});
|
|
439
|
+
setTxLoading(false);
|
|
440
|
+
if (srcChain?.chainId !== dstChain?.chainId) {
|
|
441
|
+
renderTxStatus(chainId.toString(), hash);
|
|
442
|
+
}
|
|
443
|
+
setTransactionSuccessHash(hash);
|
|
444
|
+
// onSubmit(route);
|
|
445
|
+
},
|
|
446
|
+
onError: (error) => {
|
|
447
|
+
setBackdropClickDisabled(false);
|
|
448
|
+
setTransactionError(`Transaction failed: ${error.message}`);
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
);
|
|
452
|
+
},
|
|
453
|
+
[
|
|
454
|
+
route,
|
|
455
|
+
signer,
|
|
456
|
+
srcChain,
|
|
457
|
+
srcToken,
|
|
458
|
+
debouncedAmount,
|
|
459
|
+
paymentToken,
|
|
460
|
+
slippage,
|
|
461
|
+
expressChecked,
|
|
462
|
+
],
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
// Handle form submit
|
|
194
466
|
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
|
|
195
467
|
event.preventDefault();
|
|
196
|
-
if (route)
|
|
468
|
+
if (!route) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (retrunTransactions) {
|
|
473
|
+
onSubmit(route);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
triggerTx();
|
|
197
478
|
};
|
|
198
479
|
|
|
199
480
|
const handleSwitchChain = async () => {
|
|
200
481
|
await switchChainAsync({ chainId: Number(srcChain?.chainId) });
|
|
201
482
|
};
|
|
202
483
|
|
|
484
|
+
// provides data for the main button
|
|
485
|
+
const swapButton: { text: string; fn: () => void; disabled: boolean } =
|
|
486
|
+
useMemo(() => {
|
|
487
|
+
let disabled = false;
|
|
488
|
+
|
|
489
|
+
if (transactionError) {
|
|
490
|
+
return {
|
|
491
|
+
text: transactionError,
|
|
492
|
+
fn: () => {},
|
|
493
|
+
disabled: true,
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (!signer) {
|
|
498
|
+
return {
|
|
499
|
+
text: "Connect wallet",
|
|
500
|
+
fn: () => {},
|
|
501
|
+
disabled,
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (
|
|
506
|
+
signer &&
|
|
507
|
+
srcChain &&
|
|
508
|
+
srcChain.chainId !== account.chainId?.toString()
|
|
509
|
+
) {
|
|
510
|
+
return {
|
|
511
|
+
text: "Switch chain",
|
|
512
|
+
fn: handleSwitchChain,
|
|
513
|
+
disabled,
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (!amount) {
|
|
518
|
+
return {
|
|
519
|
+
text: `Enter token amount`,
|
|
520
|
+
fn: () => {},
|
|
521
|
+
disabled: true,
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (
|
|
526
|
+
amount &&
|
|
527
|
+
balances &&
|
|
528
|
+
srcToken &&
|
|
529
|
+
srcToken.decimals &&
|
|
530
|
+
balances[srcToken?.address] !== undefined &&
|
|
531
|
+
!ethers.utils
|
|
532
|
+
.parseUnits(amount, srcToken.decimals)
|
|
533
|
+
.lt(balances[srcToken?.address] || "0")
|
|
534
|
+
) {
|
|
535
|
+
return {
|
|
536
|
+
text: "Insufficient balance",
|
|
537
|
+
fn: () => {},
|
|
538
|
+
disabled: true,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (!route) {
|
|
543
|
+
return {
|
|
544
|
+
text: `Loading route`,
|
|
545
|
+
fn: () => {},
|
|
546
|
+
disabled: true,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (isAllowanceLoading) {
|
|
551
|
+
return {
|
|
552
|
+
text: `Checking allowance`,
|
|
553
|
+
fn: () => {},
|
|
554
|
+
disabled: true,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return {
|
|
559
|
+
text: "Submit",
|
|
560
|
+
fn: () => {},
|
|
561
|
+
disabled,
|
|
562
|
+
};
|
|
563
|
+
}, [
|
|
564
|
+
account,
|
|
565
|
+
srcToken,
|
|
566
|
+
srcChain,
|
|
567
|
+
isAllowanceOk,
|
|
568
|
+
amount,
|
|
569
|
+
balances,
|
|
570
|
+
signer,
|
|
571
|
+
transactionError,
|
|
572
|
+
route,
|
|
573
|
+
isAllowanceLoading,
|
|
574
|
+
]);
|
|
575
|
+
|
|
576
|
+
// check if the express delivery will be executed
|
|
577
|
+
const isExpressDelivery = useMemo(() => {
|
|
578
|
+
let expressDeliveryFee;
|
|
579
|
+
if (!route?.xSwapFees || !route?.xSwapFees.expressDeliveryFee) {
|
|
580
|
+
expressDeliveryFee = safeBigNumberFrom("0");
|
|
581
|
+
} else {
|
|
582
|
+
expressDeliveryFee = safeBigNumberFrom(
|
|
583
|
+
route?.xSwapFees.expressDeliveryFee,
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (expressDeliveryFee.gt("0")) {
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
return false;
|
|
591
|
+
}, [route]);
|
|
592
|
+
|
|
203
593
|
return (
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
594
|
+
<>
|
|
595
|
+
{!signer ? (
|
|
596
|
+
// Connect wallet modal
|
|
597
|
+
<div className="xpay-flex xpay-flex-col xpay-gap-2 xpay-z-10 xpay-my-0 xpay-p-2 md:xpay-p-4 xpay-rounded-3xl xpay-overflow-hidden xpay-font-light sm:xpay-w-x_desktop xpay-w-screen">
|
|
598
|
+
<div className="xpay-flex xpay-w-full xpay-justify-end xpay-items-center xpay-mx-auto xpay-p-2">
|
|
599
|
+
<div
|
|
600
|
+
className="xpay-cursor-pointer xpay-text-white"
|
|
601
|
+
onClick={onClose}
|
|
602
|
+
>
|
|
603
|
+
<CloseIcon />
|
|
604
|
+
</div>
|
|
605
|
+
</div>{" "}
|
|
606
|
+
<p className="xpay-text-xl xpay-font-bold xpay-leading-8 xpay-text-center xpay-text-white">
|
|
607
|
+
Please connect the wallet first.
|
|
608
|
+
</p>
|
|
609
|
+
</div>
|
|
610
|
+
) : executingTransactions ? (
|
|
611
|
+
<div className="xpay-flex xpay-flex-col xpay-gap-2 xpay-z-10 xpay-my-0 xpay-p-2 md:xpay-p-4 xpay-rounded-3xl xpay-overflow-hidden xpay-font-light sm:xpay-w-x_desktop xpay-w-screen">
|
|
612
|
+
{transactionError ? (
|
|
613
|
+
// Tx Error modal
|
|
614
|
+
<div>
|
|
615
|
+
<div className="xpay-flex xpay-w-full xpay-justify-end xpay-items-center xpay-mx-auto xpay-p-2">
|
|
616
|
+
<div
|
|
617
|
+
className="xpay-cursor-pointer xpay-text-white"
|
|
618
|
+
onClick={onClose}
|
|
619
|
+
>
|
|
620
|
+
<CloseIcon />
|
|
621
|
+
</div>
|
|
622
|
+
</div>
|
|
623
|
+
|
|
624
|
+
<div className="xpay-flex xpay-flex-col xpay-w-full xpay-justify-center xpay-items-center xpay-mx-auto xpay-p-2 xpay-gap-4">
|
|
625
|
+
<div>
|
|
626
|
+
<ErrorIcon />
|
|
627
|
+
</div>
|
|
628
|
+
|
|
629
|
+
<div className="xpay-flex xpay-flex-col">
|
|
630
|
+
<div>
|
|
631
|
+
<p className="xpay-text-2xl xpay-font-bold xpay-leading-8 xpay-text-center xpay-text-white">
|
|
632
|
+
Transaction error!
|
|
633
|
+
</p>
|
|
634
|
+
</div>
|
|
635
|
+
<div>
|
|
636
|
+
<p className="xpay-text-sm xpay-text-center xpay-text-white xpay-opacity-50">
|
|
637
|
+
{parseWeb3Error(transactionError)}
|
|
638
|
+
</p>
|
|
639
|
+
</div>
|
|
640
|
+
</div>
|
|
641
|
+
</div>
|
|
642
|
+
</div>
|
|
643
|
+
) : transactionSuccessHash ? (
|
|
644
|
+
// Tx Success modal
|
|
645
|
+
<div>
|
|
646
|
+
<div className="xpay-flex xpay-w-full xpay-justify-end xpay-items-center xpay-mx-auto xpay-p-2">
|
|
647
|
+
<div
|
|
648
|
+
className="xpay-cursor-pointer xpay-text-white"
|
|
649
|
+
onClick={onClose}
|
|
650
|
+
>
|
|
651
|
+
<CloseIcon />
|
|
652
|
+
</div>
|
|
653
|
+
</div>
|
|
654
|
+
|
|
655
|
+
<div className="xpay-flex xpay-flex-col xpay-w-full xpay-justify-center xpay-items-center xpay-mx-auto xpay-p-2 xpay-gap-4">
|
|
656
|
+
<div>
|
|
657
|
+
<SuccessIcon />
|
|
658
|
+
</div>
|
|
659
|
+
<div className="xpay-flex xpay-flex-col">
|
|
660
|
+
<div>
|
|
661
|
+
<p className="xpay-text-2xl xpay-font-bold xpay-leading-8 xpay-text-center xpay-text-white">
|
|
662
|
+
Transaction success!
|
|
663
|
+
</p>
|
|
664
|
+
</div>
|
|
665
|
+
{srcChain?.chainId !== dstChain?.chainId ? (
|
|
666
|
+
<div>
|
|
667
|
+
<p className="xpay-text-sm xpay-text-center xpay-text-white xpay-opacity-50">
|
|
668
|
+
Approximated time of delivery:{" "}
|
|
669
|
+
{isExpressDelivery ? "30 seconds" : "30 minutes"}
|
|
670
|
+
</p>
|
|
671
|
+
</div>
|
|
672
|
+
) : (
|
|
673
|
+
<></>
|
|
674
|
+
)}
|
|
675
|
+
</div>
|
|
676
|
+
|
|
677
|
+
<div className="xpay-flex xpay-gap-4 xpay-items-center">
|
|
678
|
+
<div className="xpay-flex xpay-gap-2">
|
|
679
|
+
<div className="xpay-w-10 xpay-h-10">
|
|
680
|
+
{srcToken?.image ? (
|
|
681
|
+
<img
|
|
682
|
+
className="xpay-w-10 xpay-h-10"
|
|
683
|
+
src={srcToken?.image}
|
|
684
|
+
alt={srcToken?.name}
|
|
685
|
+
/>
|
|
686
|
+
) : (
|
|
687
|
+
<UnknownTokenLogo
|
|
688
|
+
tokenName={"?"}
|
|
689
|
+
className="xpay-w-10 xpay-h-10"
|
|
690
|
+
/>
|
|
691
|
+
)}
|
|
692
|
+
</div>
|
|
693
|
+
<div className="xpay-flex xpay-flex-col xpay-items-start">
|
|
694
|
+
<div className="xpay-flex">
|
|
695
|
+
{`${debouncedAmount} ${srcToken?.symbol}`}
|
|
696
|
+
</div>
|
|
697
|
+
<div className="xpay-text-sm xpay-text-center xpay-text-white xpay-opacity-50">
|
|
698
|
+
{srcChain?.displayName}
|
|
699
|
+
</div>
|
|
700
|
+
</div>
|
|
701
|
+
</div>
|
|
702
|
+
|
|
703
|
+
<div className="xpay-w-3.5 xpay-h-3.5">
|
|
704
|
+
<ArrowRightIcon />
|
|
705
|
+
</div>
|
|
706
|
+
|
|
707
|
+
<div className="xpay-flex xpay-gap-2">
|
|
708
|
+
<div className="xpay-w-10 xpay-h-10">
|
|
709
|
+
{(dstDisplayToken ? dstDisplayToken : dstToken)?.image ? (
|
|
710
|
+
<img
|
|
711
|
+
className="xpay-w-10 xpay-h-10"
|
|
712
|
+
src={
|
|
713
|
+
(dstDisplayToken ? dstDisplayToken : dstToken)
|
|
714
|
+
?.image
|
|
715
|
+
}
|
|
716
|
+
alt={
|
|
717
|
+
(dstDisplayToken ? dstDisplayToken : dstToken)?.name
|
|
718
|
+
}
|
|
719
|
+
/>
|
|
720
|
+
) : (
|
|
721
|
+
<UnknownTokenLogo
|
|
722
|
+
tokenName={"?"}
|
|
723
|
+
className="xpay-w-10 xpay-h-10"
|
|
724
|
+
/>
|
|
725
|
+
)}
|
|
726
|
+
</div>
|
|
727
|
+
<div className="xpay-flex xpay-flex-col xpay-items-start">
|
|
728
|
+
<div className="xpay-flex">
|
|
729
|
+
{weiToHumanReadable({
|
|
730
|
+
amount: route?.estAmountOut || "0",
|
|
731
|
+
decimals:
|
|
732
|
+
(dstDisplayToken ? dstDisplayToken : dstToken)
|
|
733
|
+
?.decimals || 18,
|
|
734
|
+
precisionFractionalPlaces: 4,
|
|
735
|
+
})}{" "}
|
|
736
|
+
{(dstDisplayToken ? dstDisplayToken : dstToken)?.symbol}
|
|
737
|
+
</div>
|
|
738
|
+
<div className="xpay-text-sm xpay-text-center xpay-text-white xpay-opacity-50">
|
|
739
|
+
{dstChain?.displayName}
|
|
740
|
+
</div>
|
|
741
|
+
</div>
|
|
742
|
+
</div>
|
|
743
|
+
</div>
|
|
744
|
+
|
|
745
|
+
<div>
|
|
746
|
+
<a
|
|
747
|
+
href={
|
|
748
|
+
srcChain?.chainId !== dstChain?.chainId
|
|
749
|
+
? `${CCIP_EXPLORER}/tx/${transactionSuccessHash}`
|
|
750
|
+
: `${
|
|
751
|
+
supportedChains.find(
|
|
752
|
+
(chain) => chain.chainId === srcChain?.chainId,
|
|
753
|
+
)?.transactionExplorer
|
|
754
|
+
}/${transactionSuccessHash}`
|
|
755
|
+
}
|
|
756
|
+
target="_blank"
|
|
757
|
+
rel="noreferrer"
|
|
758
|
+
className="xpay-flex xpay-items-center xpay-gap-2 xpay-font-bold xpay-no-underline xpay-cursor-pointer xpay-text-center"
|
|
759
|
+
aria-label="Show the transaction in the chain explorer"
|
|
760
|
+
>
|
|
761
|
+
<p className="xpay-bg-gradient-to-r xpay-from-x_blue_light xpay-to-x_blue_dark xpay-bg-clip-text xpay-text-transparent xpay-underline">
|
|
762
|
+
View details on Explorer
|
|
763
|
+
</p>
|
|
764
|
+
<div className="xpay-w-3.5 xpay-h-3.5 xpay-bg-gradient-to-r xpay-text-x_blue_dark">
|
|
765
|
+
<ArrowUpRightIcon />
|
|
766
|
+
</div>
|
|
767
|
+
</a>
|
|
768
|
+
</div>
|
|
769
|
+
</div>
|
|
770
|
+
</div>
|
|
771
|
+
) : (
|
|
772
|
+
// Tx Confirmation modal
|
|
773
|
+
<>
|
|
774
|
+
<div className="xpay-flex xpay-w-full xpay-justify-between xpay-items-center xpay-mx-auto xpay-p-2 xpay-font-light ">
|
|
775
|
+
<p className="xpay-text-white xpay-text-xl">Confirmation</p>
|
|
776
|
+
<div className="xpay-flex xpay-w-full xpay-justify-end xpay-items-center xpay-mx-auto xpay-p-2">
|
|
777
|
+
<div
|
|
778
|
+
className="xpay-cursor-pointer xpay-text-white"
|
|
779
|
+
onClick={onClose}
|
|
780
|
+
>
|
|
781
|
+
<CloseIcon />
|
|
782
|
+
</div>
|
|
783
|
+
</div>
|
|
784
|
+
</div>
|
|
785
|
+
|
|
786
|
+
<div className="xpay-flex xpay-flex-col xpay-gap-2">
|
|
787
|
+
<ConfirmationAmount
|
|
788
|
+
amount={ethers.utils
|
|
789
|
+
.parseUnits(debouncedAmount, srcToken?.decimals)
|
|
790
|
+
.toString()}
|
|
791
|
+
chain={srcChain}
|
|
792
|
+
token={srcToken}
|
|
793
|
+
type="src"
|
|
794
|
+
/>
|
|
795
|
+
</div>
|
|
796
|
+
|
|
797
|
+
<div className="xpay-flex xpay-justify-center xpay-globalBorder xpay-rounded-xl xpay-p-[5px] xpay--mt-7 xpay--mb-6 ">
|
|
798
|
+
<div className="xpay-flex xpay-items-center xpay-justify-center xpay-rounded-lg xpay-w-8 xpay-h-8 xpay-bg-gradient-to-l xpay-from-[rgba(54,129,198,1)] xpay-to-[rgba(43,74,157,1)] ">
|
|
799
|
+
<ArrowDownIcon />
|
|
800
|
+
</div>
|
|
801
|
+
</div>
|
|
802
|
+
|
|
803
|
+
<div className="xpay-flex xpay-flex-col xpay-gap-2">
|
|
804
|
+
<ConfirmationAmount
|
|
805
|
+
amount={route?.estAmountOut || "0"}
|
|
806
|
+
chain={dstChain}
|
|
807
|
+
token={dstDisplayToken ? dstDisplayToken : dstToken}
|
|
808
|
+
type="dst"
|
|
809
|
+
/>
|
|
810
|
+
</div>
|
|
811
|
+
<div className="xpay-flex xpay-flex-col xpay-globalBorder xpay-p-4 xpay-justify-center xpay-rounded-xl xpay-bg-[rgba(15,15,15,1)] xpay-relative">
|
|
812
|
+
{route?.transactions.approve && !isAllowanceOk && (
|
|
813
|
+
<>
|
|
814
|
+
<div className="xpay-flex xpay-justify-between xpay-items-center">
|
|
815
|
+
<div className="xpay-flex xpay-items-center xpay-gap-2">
|
|
816
|
+
<SignIcon />
|
|
817
|
+
<p className="xpay-opacity-50">
|
|
818
|
+
{approveTxLoading
|
|
819
|
+
? "Wait for approval confirmation"
|
|
820
|
+
: "Approve token spending"}
|
|
821
|
+
</p>
|
|
822
|
+
</div>
|
|
823
|
+
<div className="xpay-flex xpay-items-center">
|
|
824
|
+
{approveTxLoading && <Spinner width="5" height="5" />}
|
|
825
|
+
{approveTxDone && (
|
|
826
|
+
<div className="xpay-text-x_green xpay-w-5 xpay-h-5">
|
|
827
|
+
<CheckIcon />
|
|
828
|
+
</div>
|
|
829
|
+
)}
|
|
830
|
+
</div>
|
|
831
|
+
</div>
|
|
832
|
+
<div className="xpay-w-px xpay-h-6 xpay-mt-1 xpay-mb-1 xpay-ml-2.5 xpay-bg-white xpay-opacity-50"></div>
|
|
833
|
+
</>
|
|
834
|
+
)}
|
|
835
|
+
<div className="xpay-flex xpay-justify-between xpay-items-center">
|
|
836
|
+
<div className="xpay-flex xpay-items-center xpay-gap-2">
|
|
837
|
+
<SignIcon />
|
|
838
|
+
<p className="xpay-opacity-50">
|
|
839
|
+
{txLoading
|
|
840
|
+
? "Wait for transaction confirmation"
|
|
841
|
+
: "Confirm transaction"}
|
|
842
|
+
</p>
|
|
843
|
+
</div>
|
|
844
|
+
<div className="xpay-flex xpay-items-center">
|
|
845
|
+
{txLoading && <Spinner width="5" height="5" />}
|
|
846
|
+
</div>
|
|
847
|
+
</div>
|
|
848
|
+
</div>
|
|
849
|
+
</>
|
|
850
|
+
)}
|
|
851
|
+
</div>
|
|
226
852
|
) : (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
setSrcToken={setSrcToken}
|
|
234
|
-
srcChain={srcChain}
|
|
853
|
+
// XPay form
|
|
854
|
+
<form
|
|
855
|
+
className="xpay-flex xpay-flex-col xpay-gap-2 xpay-z-10 xpay-my-0 p-2 md:xpay-p-4 xpay-rounded-3xl xpay-overflow-hidden xpay-font-light sm:xpay-w-x_desktop"
|
|
856
|
+
onSubmit={handleSubmit}
|
|
857
|
+
>
|
|
858
|
+
<TopBar
|
|
235
859
|
signer={signer}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
setExceedsExpressDeliveryLimit={setExceedsExpressDeliveryLimit}
|
|
241
|
-
/>
|
|
242
|
-
<Summary
|
|
243
|
-
isGettingRoute={isGettingRoute}
|
|
244
|
-
route={route}
|
|
245
|
-
dstToken={dstToken}
|
|
246
|
-
dstChain={dstChain}
|
|
860
|
+
historyTabShown={historyTabShown}
|
|
861
|
+
setHistoryTabShown={setHistoryTabShown}
|
|
862
|
+
setSettingsShown={setSettingsShown}
|
|
863
|
+
onClose={onClose}
|
|
247
864
|
/>
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
{formError.length > 0 && <ErrorField error={formError} />}
|
|
260
|
-
{signer &&
|
|
261
|
-
srcChain &&
|
|
262
|
-
srcChain.chainId !== account.chainId?.toString() ? (
|
|
263
|
-
<Button type="button" onClick={handleSwitchChain}>
|
|
264
|
-
Switch chain
|
|
265
|
-
</Button>
|
|
865
|
+
{settingsShown && (
|
|
866
|
+
<Settings
|
|
867
|
+
expressChecked={expressChecked}
|
|
868
|
+
setExpressChecked={setExpressChecked}
|
|
869
|
+
setSettingsShown={setSettingsShown}
|
|
870
|
+
slippage={slippage}
|
|
871
|
+
setSlippage={setSlippage}
|
|
872
|
+
/>
|
|
873
|
+
)}
|
|
874
|
+
{historyTabShown ? (
|
|
875
|
+
<History signer={signer} supportedChains={supportedChains} />
|
|
266
876
|
) : (
|
|
267
|
-
<
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
877
|
+
<div className="xpay-flex xpay-flex-col xpay-gap-2">
|
|
878
|
+
<SwapPanel
|
|
879
|
+
amount={amount}
|
|
880
|
+
setAmount={setAmount}
|
|
881
|
+
srcToken={srcToken}
|
|
882
|
+
setSrcToken={setSrcToken}
|
|
883
|
+
srcChain={srcChain}
|
|
884
|
+
signer={signer}
|
|
885
|
+
balances={balances}
|
|
886
|
+
prices={prices}
|
|
887
|
+
supportedChains={supportedChains}
|
|
888
|
+
setSrcChain={setSrcChain}
|
|
889
|
+
/>
|
|
890
|
+
<Summary
|
|
891
|
+
isGettingRoute={isGettingRoute}
|
|
892
|
+
route={route}
|
|
893
|
+
dstToken={dstDisplayToken ? dstDisplayToken : dstToken}
|
|
894
|
+
dstChain={dstChain}
|
|
895
|
+
/>
|
|
896
|
+
{desc && <Description description={desc} />}
|
|
897
|
+
|
|
898
|
+
<FeesDetails
|
|
899
|
+
route={route}
|
|
900
|
+
isGettingRoute={isGettingRoute}
|
|
901
|
+
paymentToken={paymentToken}
|
|
902
|
+
dstToken={dstToken}
|
|
903
|
+
slippage={slippage}
|
|
904
|
+
feesDetailsShown={feesDetailsShown}
|
|
905
|
+
setFeesDetailsShown={setFeesDetailsShown}
|
|
906
|
+
isExpressDelivery={isExpressDelivery}
|
|
907
|
+
/>
|
|
908
|
+
{formError.length > 0 && <ErrorField error={formError} />}
|
|
909
|
+
|
|
910
|
+
<Button
|
|
911
|
+
type="submit"
|
|
912
|
+
disabled={swapButton.disabled}
|
|
913
|
+
onClick={swapButton.fn}
|
|
914
|
+
>
|
|
915
|
+
{swapButton.text}
|
|
916
|
+
</Button>
|
|
917
|
+
</div>
|
|
273
918
|
)}
|
|
274
|
-
</
|
|
919
|
+
</form>
|
|
275
920
|
)}
|
|
276
|
-
|
|
921
|
+
</>
|
|
277
922
|
);
|
|
278
923
|
};
|