@xswap-link/sdk 0.2.3 → 0.2.5
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 +17 -0
- package/dist/index.css +20 -21
- package/dist/index.d.mts +24 -13
- package/dist/index.d.ts +24 -13
- package/dist/index.js +747 -527
- package/dist/index.mjs +645 -425
- package/package.json +1 -1
- package/src/components/TxConfigForm/FeesDetails.tsx +55 -37
- package/src/components/TxConfigForm/Form.tsx +30 -7
- package/src/components/TxConfigForm/History.tsx +31 -4
- package/src/components/TxConfigForm/Summary.tsx +28 -11
- package/src/components/TxConfigForm/SwapPanel.tsx +5 -1
- package/src/components/TxConfigForm/TopBar.tsx +8 -3
- package/src/components/TxConfigForm/UsdPrice.tsx +14 -1
- package/src/components/TxConfigForm/index.tsx +10 -10
- package/src/components/TxStatusButton/index.tsx +21 -13
- package/src/components/UnknownTokenLogo/UnknownTokenLogo.tsx +14 -0
- package/src/components/WaitingForInit/index.tsx +20 -0
- package/src/components/global.css +1 -1
- package/src/config/init.tsx +75 -0
- package/src/constants/index.ts +1 -0
- package/src/index.ts +9 -1
- package/src/models/Route.ts +6 -2
- package/src/models/TokenData.ts +1 -1
- package/src/models/TransactionHistory.ts +12 -8
- package/src/models/payloads/GetRoutePayload.ts +1 -0
- package/src/models/payloads/GetSwapTxPayload.ts +1 -0
- package/src/services/api.ts +9 -0
- package/src/services/blockchain.ts +49 -0
- package/src/services/index.ts +1 -0
- package/src/services/integrations/monitoring.ts +34 -14
- package/src/services/integrations/transactions.ts +8 -3
- package/src/utils/contracts.ts +2 -4
- package/src/utils/strings.ts +4 -0
- package/tailwind.config.js +2 -2
- package/src/config/init.ts +0 -35
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { FC } from "react";
|
|
1
|
+
import { FC, useMemo } from "react";
|
|
2
2
|
import { CoinsIcon, TimerIcon, ChevronUpIcon, ChevronDownIcon } from "../icons";
|
|
3
3
|
import { safeBigNumberFrom, weiToHumanReadable } from "@src/utils";
|
|
4
4
|
import { Route, Token } from "@src/models";
|
|
5
|
+
import { Skeleton } from "@src/components";
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
route: Route | undefined;
|
|
@@ -9,6 +10,7 @@ interface Props {
|
|
|
9
10
|
paymentToken: Token | undefined;
|
|
10
11
|
dstToken: Token | undefined;
|
|
11
12
|
expressChecked: boolean;
|
|
13
|
+
exceedsExpressDeliveryLimit: boolean;
|
|
12
14
|
slippage: string | undefined;
|
|
13
15
|
feesDetailsShown: boolean;
|
|
14
16
|
setFeesDetailsShown: React.Dispatch<React.SetStateAction<boolean>>;
|
|
@@ -20,18 +22,23 @@ export const FeesDetails: FC<Props> = ({
|
|
|
20
22
|
paymentToken,
|
|
21
23
|
dstToken,
|
|
22
24
|
expressChecked,
|
|
25
|
+
exceedsExpressDeliveryLimit,
|
|
23
26
|
slippage,
|
|
24
27
|
feesDetailsShown,
|
|
25
28
|
setFeesDetailsShown,
|
|
26
29
|
}) => {
|
|
30
|
+
const isExpressDeliveryPossible = useMemo(() => {
|
|
31
|
+
return expressChecked && !exceedsExpressDeliveryLimit;
|
|
32
|
+
}, [expressChecked, exceedsExpressDeliveryLimit]);
|
|
33
|
+
|
|
27
34
|
return (
|
|
28
|
-
<div className="flex flex-col gap-3 globalBorder rounded-lg bg-[rgba(15,15,15,1)] p-4 mb-1">
|
|
29
|
-
<div className="flex w-full items-center justify-between text-xs sm:text-sm
|
|
35
|
+
<div className="flex flex-col gap-3 globalBorder rounded-lg bg-[rgba(15,15,15,1)] p-2 sm:p-4 mb-1">
|
|
36
|
+
<div className="flex w-full items-center justify-between text-xs sm:text-sm">
|
|
30
37
|
<div className="flex items-center gap-1 font-medium text-white opacity-60">
|
|
31
38
|
<CoinsIcon />
|
|
32
39
|
<div className="mr-1">Fees:</div>
|
|
33
40
|
{isGettingRoute ? (
|
|
34
|
-
<
|
|
41
|
+
<Skeleton width="w-20" height="h-4" />
|
|
35
42
|
) : (
|
|
36
43
|
` ${weiToHumanReadable({
|
|
37
44
|
amount: safeBigNumberFrom(
|
|
@@ -48,14 +55,18 @@ export const FeesDetails: FC<Props> = ({
|
|
|
48
55
|
)}
|
|
49
56
|
</div>
|
|
50
57
|
<div className="flex gap-1 items-center">
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
{route?.xSwapFees.expressDeliveryFee && !isGettingRoute && (
|
|
59
|
+
<div
|
|
60
|
+
className={`flex gap-1 items-center font-medium ${
|
|
61
|
+
isExpressDeliveryPossible
|
|
62
|
+
? "text-x_green"
|
|
63
|
+
: "text-white opacity-60"
|
|
64
|
+
}`}
|
|
65
|
+
>
|
|
66
|
+
<TimerIcon />
|
|
67
|
+
{isExpressDeliveryPossible ? "Fast ~ 30sec " : "Normal ~ 30min"}
|
|
68
|
+
</div>
|
|
69
|
+
)}
|
|
59
70
|
<div
|
|
60
71
|
onClick={() => setFeesDetailsShown((x) => !x)}
|
|
61
72
|
className="font-medium text-white opacity-60 cursor-pointer flex items-center w-[15px] h-[9px]"
|
|
@@ -65,37 +76,44 @@ export const FeesDetails: FC<Props> = ({
|
|
|
65
76
|
</div>
|
|
66
77
|
</div>
|
|
67
78
|
{feesDetailsShown && (
|
|
68
|
-
<div className="flex w-full items-center justify-between ">
|
|
79
|
+
<div className="flex w-full items-center justify-between gap-2">
|
|
69
80
|
<div className="flex flex-col text-[10px] gap-1">
|
|
70
|
-
<div className="font-medium text-white opacity-60">
|
|
71
|
-
CCIP Fee
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
<div className="flex justify-between font-medium text-white opacity-60 gap-1">
|
|
82
|
+
<div>CCIP Fee:</div>
|
|
83
|
+
<div className="whitespace-nowrap">
|
|
84
|
+
{` ${weiToHumanReadable({
|
|
85
|
+
amount: route?.xSwapFees.ccipFee || "0",
|
|
86
|
+
decimals: 18,
|
|
87
|
+
precisionFractionalPlaces: 5,
|
|
88
|
+
})} ${paymentToken?.symbol}`}
|
|
89
|
+
</div>
|
|
77
90
|
</div>
|
|
78
|
-
<div className="font-medium text-white opacity-60">
|
|
79
|
-
Native Fee
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
<div className="flex justify-between font-medium text-white opacity-60 gap-1">
|
|
92
|
+
<div>Native Fee:</div>
|
|
93
|
+
<div className="whitespace-nowrap">
|
|
94
|
+
{` ${weiToHumanReadable({
|
|
95
|
+
amount: route?.xSwapFees.xSwapFee.nativeFee || "0",
|
|
96
|
+
decimals: 18,
|
|
97
|
+
precisionFractionalPlaces: 5,
|
|
98
|
+
})} ${paymentToken?.symbol}`}
|
|
99
|
+
</div>
|
|
85
100
|
</div>
|
|
86
101
|
</div>
|
|
87
102
|
<div className="flex flex-col text-[10px] gap-1">
|
|
88
|
-
<div className="font-medium text-white opacity-60">
|
|
89
|
-
Slippage
|
|
103
|
+
<div className="flex justify-between font-medium text-white opacity-60 gap-1">
|
|
104
|
+
<div>Slippage:</div>
|
|
105
|
+
<div className="whitespace-nowrap">{`${slippage}%`}</div>
|
|
90
106
|
</div>
|
|
91
|
-
<div className="font-medium text-white opacity-60">
|
|
92
|
-
Min amount out
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
107
|
+
<div className="flex justify-between font-medium text-white opacity-60 gap-1">
|
|
108
|
+
<div>Min amount out:</div>
|
|
109
|
+
<div className="whitespace-nowrap">
|
|
110
|
+
{weiToHumanReadable({
|
|
111
|
+
amount: route?.minAmountOut || "0",
|
|
112
|
+
decimals: dstToken?.decimals || 18,
|
|
113
|
+
precisionFractionalPlaces: 5,
|
|
114
|
+
})}{" "}
|
|
115
|
+
{dstToken?.symbol}
|
|
116
|
+
</div>
|
|
99
117
|
</div>
|
|
100
118
|
</div>
|
|
101
119
|
</div>
|
|
@@ -3,7 +3,7 @@ import React, { FormEvent, useEffect, useState } from "react";
|
|
|
3
3
|
import { ethers } from "ethers";
|
|
4
4
|
import { useAccount, useSwitchChain } from "wagmi";
|
|
5
5
|
import { Chain, Route, Token, TokenBalances, TokenPrices } from "@src/models";
|
|
6
|
-
import { getPrices, getRoute } from "@src/services";
|
|
6
|
+
import { getCustomTokenData, getPrices, getRoute } from "@src/services";
|
|
7
7
|
import { getBalances } from "@src/utils";
|
|
8
8
|
import { ROUTE_TIMEOUT_MS } from "@src/constants";
|
|
9
9
|
import { TxConfigFormProps } from "@src/components";
|
|
@@ -21,14 +21,17 @@ import { DEFAULT_SOURCE_CHAIN_ID } from "@src/constants";
|
|
|
21
21
|
import { Button } from "./Button";
|
|
22
22
|
|
|
23
23
|
export const Form = ({
|
|
24
|
+
integratorId,
|
|
24
25
|
dstChainId,
|
|
25
26
|
dstTokenAddr,
|
|
26
27
|
customContractCalls,
|
|
27
28
|
desc,
|
|
28
29
|
supportedChains,
|
|
29
30
|
onSubmit,
|
|
31
|
+
onClose,
|
|
30
32
|
}: TxConfigFormProps & {
|
|
31
33
|
onSubmit: (route: Route) => void;
|
|
34
|
+
onClose: () => void;
|
|
32
35
|
}) => {
|
|
33
36
|
const [signer, setSigner] = useState<string | undefined>();
|
|
34
37
|
const [dstChain, setDstChain] = useState<Chain>();
|
|
@@ -47,6 +50,8 @@ export const Form = ({
|
|
|
47
50
|
const [formError, setFormError] = useState("");
|
|
48
51
|
const [slippage, setSlippage] = useState<string>("1.5");
|
|
49
52
|
const [feesDetailsShown, setFeesDetailsShown] = useState(false);
|
|
53
|
+
const [exceedsExpressDeliveryLimit, setExceedsExpressDeliveryLimit] =
|
|
54
|
+
useState(false);
|
|
50
55
|
|
|
51
56
|
const debouncedAmount = useDebounce(amount, 1000);
|
|
52
57
|
const account = useAccount();
|
|
@@ -73,15 +78,29 @@ export const Form = ({
|
|
|
73
78
|
}, [supportedChains, dstChainId]);
|
|
74
79
|
|
|
75
80
|
useEffect(() => {
|
|
76
|
-
|
|
77
|
-
dstChain
|
|
81
|
+
(async () => {
|
|
82
|
+
if (!dstChain) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let dstTokenResult = dstChain?.tokens.find(
|
|
78
87
|
(token) => token.address.toLowerCase() === dstTokenAddr.toLowerCase(),
|
|
79
|
-
)
|
|
80
|
-
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (!dstTokenResult) {
|
|
91
|
+
dstTokenResult = await getCustomTokenData(
|
|
92
|
+
dstChain,
|
|
93
|
+
dstTokenAddr.toLowerCase(),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
setDstToken(dstTokenResult);
|
|
98
|
+
})();
|
|
81
99
|
}, [dstChain]);
|
|
82
100
|
|
|
83
101
|
useEffect(() => {
|
|
84
102
|
if (
|
|
103
|
+
integratorId &&
|
|
85
104
|
srcChain &&
|
|
86
105
|
srcToken &&
|
|
87
106
|
dstChain &&
|
|
@@ -100,6 +119,7 @@ export const Form = ({
|
|
|
100
119
|
`Configuration error: selected token ($${srcToken.symbol} ${srcToken.name}) has unknown decimals param.`,
|
|
101
120
|
);
|
|
102
121
|
getRoute({
|
|
122
|
+
integratorId,
|
|
103
123
|
fromAmount: ethers.utils
|
|
104
124
|
.parseUnits(debouncedAmount, srcToken.decimals)
|
|
105
125
|
.toString(),
|
|
@@ -111,7 +131,7 @@ export const Form = ({
|
|
|
111
131
|
toToken: dstTokenAddr,
|
|
112
132
|
paymentToken: paymentToken.address,
|
|
113
133
|
slippage: Number(slippage),
|
|
114
|
-
expressDelivery: expressChecked,
|
|
134
|
+
expressDelivery: expressChecked && !exceedsExpressDeliveryLimit,
|
|
115
135
|
customContractCalls,
|
|
116
136
|
})
|
|
117
137
|
.then((response) => {
|
|
@@ -182,7 +202,7 @@ export const Form = ({
|
|
|
182
202
|
|
|
183
203
|
return (
|
|
184
204
|
<form
|
|
185
|
-
className="flex flex-col gap-2 z-10 my-0
|
|
205
|
+
className="flex flex-col gap-2 z-10 my-0 p-2 md:p-4 rounded-3xl overflow-hidden font-light sm:w-x_desktop"
|
|
186
206
|
onSubmit={handleSubmit}
|
|
187
207
|
>
|
|
188
208
|
<TopBar
|
|
@@ -190,6 +210,7 @@ export const Form = ({
|
|
|
190
210
|
historyTabShown={historyTabShown}
|
|
191
211
|
setHistoryTabShown={setHistoryTabShown}
|
|
192
212
|
setSettingsShown={setSettingsShown}
|
|
213
|
+
onClose={onClose}
|
|
193
214
|
/>
|
|
194
215
|
{settingsShown && (
|
|
195
216
|
<Settings
|
|
@@ -216,6 +237,7 @@ export const Form = ({
|
|
|
216
237
|
prices={prices}
|
|
217
238
|
supportedChains={supportedChains}
|
|
218
239
|
setSrcChain={setSrcChain}
|
|
240
|
+
setExceedsExpressDeliveryLimit={setExceedsExpressDeliveryLimit}
|
|
219
241
|
/>
|
|
220
242
|
<Summary
|
|
221
243
|
isGettingRoute={isGettingRoute}
|
|
@@ -229,6 +251,7 @@ export const Form = ({
|
|
|
229
251
|
paymentToken={paymentToken}
|
|
230
252
|
dstToken={dstToken}
|
|
231
253
|
expressChecked={expressChecked}
|
|
254
|
+
exceedsExpressDeliveryLimit={exceedsExpressDeliveryLimit}
|
|
232
255
|
slippage={slippage}
|
|
233
256
|
feesDetailsShown={feesDetailsShown}
|
|
234
257
|
setFeesDetailsShown={setFeesDetailsShown}
|
|
@@ -21,15 +21,42 @@ export const History: FC<Props> = ({ signer, supportedChains }) => {
|
|
|
21
21
|
const fetchedTransactions: Transaction[] = [];
|
|
22
22
|
if (downloadedHistory) {
|
|
23
23
|
for (const entry of downloadedHistory.history) {
|
|
24
|
+
let status: TransactionStatus = "IN_PROGRESS";
|
|
25
|
+
|
|
26
|
+
// single chain tx
|
|
24
27
|
if (!entry.source) {
|
|
25
28
|
continue;
|
|
26
29
|
}
|
|
27
|
-
|
|
28
|
-
if (entry.failed)
|
|
30
|
+
|
|
31
|
+
if (entry.failed) {
|
|
32
|
+
status = "REVERTED";
|
|
33
|
+
}
|
|
29
34
|
if (!!entry.target) {
|
|
30
35
|
status = "DONE";
|
|
31
|
-
}
|
|
32
|
-
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (entry.transferType === "SINGLE_CHAIN") {
|
|
39
|
+
if (!entry.target) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const blockTimestampMs = new Date(entry.target.blockTime).getTime();
|
|
44
|
+
const estimatedDeliveryTimestamp = blockTimestampMs / 1000;
|
|
45
|
+
|
|
46
|
+
fetchedTransactions.push({
|
|
47
|
+
hash: entry.target.transactionHash,
|
|
48
|
+
timestamp: blockTimestampMs / 1000,
|
|
49
|
+
sourceChainId: entry.target.blockchainId,
|
|
50
|
+
targetChainId: entry.target.blockchainId,
|
|
51
|
+
amountWei: entry.source.tokenAmount,
|
|
52
|
+
tokenAddress: entry.source.tokenAddress,
|
|
53
|
+
tokenOutAddress: entry.target?.tokenAmount,
|
|
54
|
+
tokenOutAmount: entry.target?.tokenAmount,
|
|
55
|
+
estimatedDeliveryTimestamp,
|
|
56
|
+
status,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
continue;
|
|
33
60
|
}
|
|
34
61
|
|
|
35
62
|
const blockTimestampMs = new Date(entry.source.blockTime).getTime();
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { weiToHumanReadable } from "@src/utils";
|
|
3
3
|
import { Chain, Route, Token, TokenPrices } from "@src/models";
|
|
4
4
|
import { ArrowDownIcon } from "../icons";
|
|
5
5
|
import { UsdPrice } from "@src/components/TxConfigForm/UsdPrice";
|
|
6
6
|
import { getPrices } from "@src/services";
|
|
7
7
|
import { Skeleton } from "@src/components";
|
|
8
|
+
import { UnknownTokenLogo } from "../UnknownTokenLogo/UnknownTokenLogo";
|
|
8
9
|
|
|
9
10
|
interface Props {
|
|
10
11
|
isGettingRoute: boolean;
|
|
@@ -53,20 +54,35 @@ export const Summary: FC<Props> = ({
|
|
|
53
54
|
) : (
|
|
54
55
|
<div className="flex gap-2 items-center text-white text-xl sm:text-3xl">
|
|
55
56
|
{amountReadable}
|
|
56
|
-
<div className="w-4 sm:w-6 h-4 sm:h-6">
|
|
57
|
-
<img src={dstToken?.image} alt={dstToken?.name} />
|
|
58
|
-
</div>
|
|
59
|
-
<p className="text-base sm:text-xl">{dstToken?.symbol}</p>
|
|
60
57
|
</div>
|
|
61
58
|
)}
|
|
62
59
|
</div>
|
|
63
|
-
<div className="flex flex-col gap-1 text-sm">
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
<div className="flex flex-col items-end gap-1 text-sm">
|
|
61
|
+
<div className="flex justify-center items-center gap-1">
|
|
62
|
+
<div className="w-5 h-5">
|
|
63
|
+
{dstToken?.image ? (
|
|
64
|
+
<img
|
|
65
|
+
className="w-5 h-5"
|
|
66
|
+
src={dstToken?.image}
|
|
67
|
+
alt={dstToken?.name}
|
|
68
|
+
/>
|
|
69
|
+
) : (
|
|
70
|
+
<UnknownTokenLogo
|
|
71
|
+
tokenName={"?"}
|
|
72
|
+
className="token-select__generated-logo"
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
<p className="text-base sm:text-xl">{dstToken?.name}</p>
|
|
77
|
+
</div>
|
|
78
|
+
<div className="flex justify-center items-center gap-1">
|
|
79
|
+
<p className="text-[rgba(255,255,255,0.6)] text-right">on </p>
|
|
80
|
+
<div className="flex items-center gap-1 text-white">
|
|
81
|
+
<div className="w-4 h-4">
|
|
82
|
+
<img src={dstChain?.image} alt={dstChain?.name} />
|
|
83
|
+
</div>
|
|
84
|
+
<div>{dstChain?.displayName}</div>
|
|
68
85
|
</div>
|
|
69
|
-
<div>{dstChain?.displayName}</div>
|
|
70
86
|
</div>
|
|
71
87
|
</div>
|
|
72
88
|
</div>
|
|
@@ -75,6 +91,7 @@ export const Summary: FC<Props> = ({
|
|
|
75
91
|
token={dstToken}
|
|
76
92
|
amount={amountReadable}
|
|
77
93
|
loading={isGettingRoute}
|
|
94
|
+
type="dst"
|
|
78
95
|
/>
|
|
79
96
|
<div className="absolute right-[50%] top-0 translate-x-1/2 translate-y-[-60%] globalBorder rounded-xl p-[5px] bg-[rgba(15,15,15,1)]">
|
|
80
97
|
<div className=" flex items-center justify-center rounded-lg w-8 h-8 bg-gradient-to-l from-[rgba(54,129,198,1)] to-[rgba(43,74,157,1)] ">
|
|
@@ -19,6 +19,7 @@ interface Props {
|
|
|
19
19
|
balances: TokenBalances | undefined;
|
|
20
20
|
prices: TokenPrices | undefined;
|
|
21
21
|
supportedChains: Chain[];
|
|
22
|
+
setExceedsExpressDeliveryLimit: (exceeds: boolean) => void;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export const SwapPanel: FC<Props> = ({
|
|
@@ -32,6 +33,7 @@ export const SwapPanel: FC<Props> = ({
|
|
|
32
33
|
balances,
|
|
33
34
|
prices,
|
|
34
35
|
supportedChains,
|
|
36
|
+
setExceedsExpressDeliveryLimit,
|
|
35
37
|
}) => {
|
|
36
38
|
const [chainListShown, setChainListShown] = useState(false);
|
|
37
39
|
const [tokenListShown, setTokenListShown] = useState(false);
|
|
@@ -61,7 +63,7 @@ export const SwapPanel: FC<Props> = ({
|
|
|
61
63
|
weiToHumanReadable({
|
|
62
64
|
amount: balances[srcToken.address]?.toString() || "0",
|
|
63
65
|
decimals: srcToken.decimals,
|
|
64
|
-
precisionFractionalPlaces:
|
|
66
|
+
precisionFractionalPlaces: srcToken.decimals,
|
|
65
67
|
}),
|
|
66
68
|
);
|
|
67
69
|
};
|
|
@@ -109,6 +111,8 @@ export const SwapPanel: FC<Props> = ({
|
|
|
109
111
|
token={srcToken}
|
|
110
112
|
amount={amount}
|
|
111
113
|
loading={false}
|
|
114
|
+
type="src"
|
|
115
|
+
setExceedsExpressDeliveryLimit={setExceedsExpressDeliveryLimit}
|
|
112
116
|
/>
|
|
113
117
|
</div>
|
|
114
118
|
</div>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
2
|
import { shortAddress } from "@src/utils";
|
|
3
|
-
import { SettingsIcon, HistoryIcon } from "../icons";
|
|
3
|
+
import { SettingsIcon, HistoryIcon, CloseIcon } from "../icons";
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
6
|
signer: string | undefined;
|
|
7
7
|
setSettingsShown: React.Dispatch<React.SetStateAction<boolean>>;
|
|
8
8
|
historyTabShown: boolean;
|
|
9
9
|
setHistoryTabShown: React.Dispatch<React.SetStateAction<boolean>>;
|
|
10
|
+
onClose: () => void;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export const TopBar: FC<Props> = ({
|
|
@@ -14,15 +15,16 @@ export const TopBar: FC<Props> = ({
|
|
|
14
15
|
setSettingsShown,
|
|
15
16
|
setHistoryTabShown,
|
|
16
17
|
historyTabShown,
|
|
18
|
+
onClose,
|
|
17
19
|
}) => {
|
|
18
20
|
return (
|
|
19
|
-
<div className="flex w-full justify-between items-center mx-auto
|
|
21
|
+
<div className="flex w-full justify-between items-center mx-auto p-2">
|
|
20
22
|
<div className="rounded-lg text-[rgba(255,255,255,0.6)] text-xs sm:text-base whitespace-nowrap">
|
|
21
23
|
{signer
|
|
22
24
|
? `Connected wallet: ${shortAddress(signer)}`
|
|
23
25
|
: `Wallet disconnected`}
|
|
24
26
|
</div>
|
|
25
|
-
<div className="flex gap-2">
|
|
27
|
+
<div className="flex gap-2 justify-center items-center">
|
|
26
28
|
{!historyTabShown && (
|
|
27
29
|
<div
|
|
28
30
|
onClick={() => setSettingsShown(true)}
|
|
@@ -47,6 +49,9 @@ export const TopBar: FC<Props> = ({
|
|
|
47
49
|
<div>Back</div>
|
|
48
50
|
)}
|
|
49
51
|
</div>
|
|
52
|
+
<div className="cursor-pointer text-white" onClick={onClose}>
|
|
53
|
+
<CloseIcon />
|
|
54
|
+
</div>
|
|
50
55
|
</div>
|
|
51
56
|
</div>
|
|
52
57
|
);
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { Alert, Skeleton } from "@src/components";
|
|
2
2
|
import { Token, TokenPrices } from "@src/models";
|
|
3
3
|
import { FC, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { EXPRESS_DELIVERY_LIMIT } from "@src/constants";
|
|
4
5
|
|
|
5
6
|
type Props = {
|
|
6
7
|
prices: TokenPrices | undefined;
|
|
7
8
|
token: Token | undefined;
|
|
8
9
|
amount: string | undefined;
|
|
9
10
|
loading: boolean;
|
|
11
|
+
type: "src" | "dst";
|
|
12
|
+
setExceedsExpressDeliveryLimit?: (exceeds: boolean) => void;
|
|
10
13
|
};
|
|
11
14
|
|
|
12
15
|
export const UsdPrice: FC<Props> = ({
|
|
@@ -14,12 +17,22 @@ export const UsdPrice: FC<Props> = ({
|
|
|
14
17
|
token,
|
|
15
18
|
amount = "0",
|
|
16
19
|
loading = false,
|
|
20
|
+
type,
|
|
21
|
+
setExceedsExpressDeliveryLimit,
|
|
17
22
|
}) => {
|
|
18
23
|
const [usdPrice, setUsdPrice] = useState<string>("0.00");
|
|
19
24
|
|
|
20
25
|
useEffect(() => {
|
|
21
26
|
if (token && prices && prices[token.address]) {
|
|
22
|
-
|
|
27
|
+
const newUsdPrice = (
|
|
28
|
+
Number(amount) * Number(prices[token.address])
|
|
29
|
+
).toFixed(2);
|
|
30
|
+
if (type === "src" && setExceedsExpressDeliveryLimit) {
|
|
31
|
+
setExceedsExpressDeliveryLimit(
|
|
32
|
+
Number(newUsdPrice) > EXPRESS_DELIVERY_LIMIT,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
setUsdPrice(newUsdPrice);
|
|
23
36
|
}
|
|
24
37
|
}, [token, prices, amount]);
|
|
25
38
|
|
|
@@ -2,13 +2,13 @@ import "@src/global.css";
|
|
|
2
2
|
import { MouseEvent, useMemo } from "react";
|
|
3
3
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
4
4
|
import { WagmiProvider } from "wagmi";
|
|
5
|
-
import { getWagmiConfig, xswapRoot } from "@src/config";
|
|
5
|
+
import { getWagmiConfig, waitForInitialization, xswapRoot } from "@src/config";
|
|
6
6
|
import { Chain, ContractCall, Route } from "@src/models";
|
|
7
|
-
import { CloseIcon } from "@src/components/icons/CloseIcon";
|
|
8
7
|
import { PoweredBy } from "@src/components/TxConfigForm/PoweredBy";
|
|
9
8
|
import { Form } from "./Form";
|
|
10
9
|
|
|
11
10
|
export type TxConfigFormProps = {
|
|
11
|
+
integratorId: string;
|
|
12
12
|
dstChainId: string;
|
|
13
13
|
dstTokenAddr: string;
|
|
14
14
|
customContractCalls: ContractCall[];
|
|
@@ -17,6 +17,7 @@ export type TxConfigFormProps = {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
const TxConfigForm = ({
|
|
20
|
+
integratorId,
|
|
20
21
|
dstChainId,
|
|
21
22
|
dstTokenAddr,
|
|
22
23
|
customContractCalls,
|
|
@@ -49,21 +50,17 @@ const TxConfigForm = ({
|
|
|
49
50
|
className="top-0 left-0 right-0 bottom-0 bg-[rgba(0,0,0,0.8)] fixed flex items-center justify-center z-10"
|
|
50
51
|
onClick={onBackdropClick}
|
|
51
52
|
>
|
|
52
|
-
<div className="relative bg-black rounded-3xl
|
|
53
|
+
<div className="relative bg-black rounded-3xl overflow-auto text-white border-2 border-solid border-[rgba(255,255,255,0.1)]">
|
|
53
54
|
<Form
|
|
55
|
+
integratorId={integratorId}
|
|
54
56
|
dstChainId={dstChainId}
|
|
55
57
|
dstTokenAddr={dstTokenAddr}
|
|
56
58
|
customContractCalls={customContractCalls}
|
|
57
59
|
desc={desc}
|
|
58
60
|
supportedChains={supportedChains}
|
|
59
61
|
onSubmit={onSubmit}
|
|
62
|
+
onClose={onClose}
|
|
60
63
|
/>
|
|
61
|
-
<div
|
|
62
|
-
className="absolute top-7 right-4 cursor-pointer text-white"
|
|
63
|
-
onClick={onClose}
|
|
64
|
-
>
|
|
65
|
-
<CloseIcon />
|
|
66
|
-
</div>
|
|
67
64
|
<PoweredBy />
|
|
68
65
|
</div>
|
|
69
66
|
</div>
|
|
@@ -73,6 +70,7 @@ const TxConfigForm = ({
|
|
|
73
70
|
};
|
|
74
71
|
|
|
75
72
|
export const openTxConfigForm = async ({
|
|
73
|
+
integratorId,
|
|
76
74
|
dstChainId,
|
|
77
75
|
dstTokenAddr,
|
|
78
76
|
customContractCalls,
|
|
@@ -80,9 +78,11 @@ export const openTxConfigForm = async ({
|
|
|
80
78
|
supportedChains,
|
|
81
79
|
}: TxConfigFormProps): Promise<Route> => {
|
|
82
80
|
try {
|
|
83
|
-
return await new Promise((resolve) => {
|
|
81
|
+
return await new Promise(async (resolve) => {
|
|
82
|
+
await waitForInitialization();
|
|
84
83
|
xswapRoot.render(
|
|
85
84
|
<TxConfigForm
|
|
85
|
+
integratorId={integratorId}
|
|
86
86
|
dstChainId={dstChainId}
|
|
87
87
|
dstTokenAddr={dstTokenAddr}
|
|
88
88
|
customContractCalls={customContractCalls}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "../icons";
|
|
10
10
|
import { MonitoredTransaction } from "@src/models";
|
|
11
11
|
import { txStatusRoot } from "@src/config";
|
|
12
|
+
import { UnknownTokenLogo } from "../UnknownTokenLogo/UnknownTokenLogo";
|
|
12
13
|
|
|
13
14
|
interface Props {
|
|
14
15
|
transaction: MonitoredTransaction;
|
|
@@ -16,15 +17,14 @@ interface Props {
|
|
|
16
17
|
|
|
17
18
|
export const TxStatusButton: FC<Props> = ({ transaction }) => {
|
|
18
19
|
const {
|
|
19
|
-
fromChain,
|
|
20
|
-
fromChainImage,
|
|
21
|
-
fromToken,
|
|
22
|
-
fromTokenImage,
|
|
23
|
-
fromAmount,
|
|
24
|
-
toChain,
|
|
25
|
-
toChainImage,
|
|
20
|
+
srcChain: fromChain,
|
|
21
|
+
srcChainImage: fromChainImage,
|
|
22
|
+
srcToken: fromToken,
|
|
23
|
+
srcTokenImage: fromTokenImage,
|
|
24
|
+
srcAmount: fromAmount,
|
|
25
|
+
dstChain: toChain,
|
|
26
|
+
dstChainImage: toChainImage,
|
|
26
27
|
isDone,
|
|
27
|
-
txHash,
|
|
28
28
|
explorer,
|
|
29
29
|
} = transaction;
|
|
30
30
|
const [isWide, setIsWide] = useState(false);
|
|
@@ -70,11 +70,19 @@ export const TxStatusButton: FC<Props> = ({ transaction }) => {
|
|
|
70
70
|
<div>Sent</div>
|
|
71
71
|
<div>{fromAmount}</div>
|
|
72
72
|
<div>{fromToken}</div>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
|
|
74
|
+
{fromTokenImage ? (
|
|
75
|
+
<img
|
|
76
|
+
className="w-5 h-5"
|
|
77
|
+
src={fromTokenImage}
|
|
78
|
+
alt="source token"
|
|
79
|
+
/>
|
|
80
|
+
) : (
|
|
81
|
+
<UnknownTokenLogo
|
|
82
|
+
tokenName={"?"}
|
|
83
|
+
className="token-select__generated-logo"
|
|
84
|
+
/>
|
|
85
|
+
)}
|
|
78
86
|
</div>
|
|
79
87
|
</div>
|
|
80
88
|
<a
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
tokenName: string;
|
|
3
|
+
className?: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const UnknownTokenLogo = ({ tokenName, className }: Props) => {
|
|
7
|
+
return (
|
|
8
|
+
<div
|
|
9
|
+
className={`w-5 h-5 rounded-full bg-white shadow-sm flex items-center justify-center text-black ${className}`}
|
|
10
|
+
>
|
|
11
|
+
{tokenName.substring(0, 1)}
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const WaitingForInit = () => {
|
|
2
|
+
return (
|
|
3
|
+
<div
|
|
4
|
+
style={{
|
|
5
|
+
zIndex: 10,
|
|
6
|
+
top: 0,
|
|
7
|
+
right: 0,
|
|
8
|
+
bottom: 0,
|
|
9
|
+
left: 0,
|
|
10
|
+
backgroundColor: "rgba(0,0,0,0.8)",
|
|
11
|
+
position: "fixed",
|
|
12
|
+
display: "flex",
|
|
13
|
+
alignItems: "center",
|
|
14
|
+
justifyContent: "center",
|
|
15
|
+
}}
|
|
16
|
+
>
|
|
17
|
+
Waiting for XPay initialization ...
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
};
|