@xswap-link/sdk 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/index.css +92 -33
- package/dist/index.d.mts +60 -155
- package/dist/index.d.ts +60 -155
- package/dist/index.js +915 -1841
- package/dist/index.mjs +867 -1800
- package/package.json +1 -1
- package/src/components/Skeleton/index.tsx +8 -5
- package/src/components/TxConfigForm/FeesDetails.tsx +5 -5
- package/src/components/TxConfigForm/Form.tsx +10 -3
- package/src/components/TxConfigForm/History.tsx +1 -1
- package/src/components/TxConfigForm/HistoryCard.tsx +19 -40
- package/src/components/TxConfigForm/Summary.tsx +57 -28
- package/src/components/TxConfigForm/SwapPanel.tsx +70 -77
- package/src/components/TxConfigForm/TokenPicker.tsx +2 -2
- package/src/components/TxConfigForm/TopBar.tsx +2 -2
- package/src/components/TxConfigForm/UsdPrice.tsx +41 -0
- package/src/components/TxConfigForm/index.tsx +1 -2
- package/src/components/TxHistoryButton/index.tsx +150 -0
- package/src/components/icons/ArrowLeftIcon.tsx +16 -0
- package/src/components/icons/ChevronUpIcon.tsx +1 -6
- package/src/components/icons/CircularProgressIcon.tsx +13 -15
- package/src/components/icons/XSwapLogo.tsx +98 -0
- package/src/components/icons/index.ts +2 -0
- package/src/components/index.ts +1 -0
- package/src/constants/index.ts +1 -0
- package/src/contracts/abi/index.ts +0 -2
- package/src/contracts/addresses.ts +6 -0
- package/src/models/Addresses.ts +1 -0
- package/src/models/TransactionHistory.ts +44 -29
- package/src/services/integrations/transactions.ts +166 -1
- package/src/utils/index.ts +7 -0
- package/tailwind.config.js +6 -1
- package/tsconfig.json +3 -7
- package/src/contracts/abi/XSwapRouter.json +0 -1242
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
type Props = {
|
|
4
|
+
width: string;
|
|
5
|
+
height: string;
|
|
6
|
+
other?: string;
|
|
5
7
|
};
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
export const Skeleton = ({ width, height }: Props) => {
|
|
10
|
+
return (
|
|
11
|
+
<div className={`bg-current rounded animate-pulse ${width} ${height}`} />
|
|
12
|
+
);
|
|
10
13
|
};
|
|
@@ -26,8 +26,8 @@ export const FeesDetails: FC<Props> = ({
|
|
|
26
26
|
}) => {
|
|
27
27
|
return (
|
|
28
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">
|
|
30
|
-
<div className="flex items-center gap-1
|
|
29
|
+
<div className="flex w-full items-center justify-between text-xs sm:text-sm ">
|
|
30
|
+
<div className="flex items-center gap-1 font-medium text-white opacity-60">
|
|
31
31
|
<CoinsIcon />
|
|
32
32
|
<div className="mr-1">Fees:</div>
|
|
33
33
|
{isGettingRoute ? (
|
|
@@ -47,9 +47,9 @@ export const FeesDetails: FC<Props> = ({
|
|
|
47
47
|
})} ${paymentToken?.symbol}`
|
|
48
48
|
)}
|
|
49
49
|
</div>
|
|
50
|
-
<div className="flex gap-1">
|
|
50
|
+
<div className="flex gap-1 items-center">
|
|
51
51
|
<div
|
|
52
|
-
className={`flex gap-1
|
|
52
|
+
className={`flex gap-1 items-center font-medium ${
|
|
53
53
|
expressChecked ? "text-x_green" : "text-white opacity-60"
|
|
54
54
|
}`}
|
|
55
55
|
>
|
|
@@ -58,7 +58,7 @@ export const FeesDetails: FC<Props> = ({
|
|
|
58
58
|
</div>
|
|
59
59
|
<div
|
|
60
60
|
onClick={() => setFeesDetailsShown((x) => !x)}
|
|
61
|
-
className="
|
|
61
|
+
className="font-medium text-white opacity-60 cursor-pointer flex items-center w-[15px] h-[9px]"
|
|
62
62
|
>
|
|
63
63
|
{feesDetailsShown ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
|
64
64
|
</div>
|
|
@@ -94,9 +94,13 @@ export const Form = ({
|
|
|
94
94
|
}, ROUTE_TIMEOUT_MS);
|
|
95
95
|
setIsGettingRoute(true);
|
|
96
96
|
setFeesDetailsShown(false);
|
|
97
|
+
if (!srcToken.decimals)
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Configuration error: selected token ($${srcToken.symbol} ${srcToken.name}) has unknown decimals param.`,
|
|
100
|
+
);
|
|
97
101
|
getRoute({
|
|
98
102
|
fromAmount: ethers.utils
|
|
99
|
-
.parseUnits(debouncedAmount, srcToken
|
|
103
|
+
.parseUnits(debouncedAmount, srcToken.decimals)
|
|
100
104
|
.toString(),
|
|
101
105
|
fromAddress: signer || ADDRESSES[srcChain.chainId]!.FeeCollector,
|
|
102
106
|
fromChain: srcChain.chainId,
|
|
@@ -214,7 +218,6 @@ export const Form = ({
|
|
|
214
218
|
/>
|
|
215
219
|
<Summary
|
|
216
220
|
isGettingRoute={isGettingRoute}
|
|
217
|
-
amount={amount}
|
|
218
221
|
route={route}
|
|
219
222
|
dstToken={dstToken}
|
|
220
223
|
dstChain={dstChain}
|
|
@@ -231,7 +234,11 @@ export const Form = ({
|
|
|
231
234
|
/>
|
|
232
235
|
{formError.length > 0 && <ErrorField error={formError} />}
|
|
233
236
|
{srcChain && srcChain.chainId !== account.chainId?.toString() ? (
|
|
234
|
-
<button
|
|
237
|
+
<button
|
|
238
|
+
disabled={!signer}
|
|
239
|
+
type="button"
|
|
240
|
+
onClick={handleSwitchChain}
|
|
241
|
+
>
|
|
235
242
|
Switch chain
|
|
236
243
|
</button>
|
|
237
244
|
) : (
|
|
@@ -80,7 +80,7 @@ export const History: FC<Props> = ({ signer, supportedChains }) => {
|
|
|
80
80
|
|
|
81
81
|
return (
|
|
82
82
|
<div className="flex items-center justify-center w-full">
|
|
83
|
-
<div className="w-full h-
|
|
83
|
+
<div className="w-full h-96 overflow-scroll overflow-x-hidden">
|
|
84
84
|
{fetchedHistory?.length === 0 && historyLoadedOnce && (
|
|
85
85
|
<div className="w-full text-center py-4 px-0 text-[rgb(158,158,158)]">
|
|
86
86
|
Your history is empty...
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FC, useCallback, useMemo } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { getDate } from "@src/utils";
|
|
3
3
|
import { Transaction, Chain, Token } from "@src/models";
|
|
4
4
|
import { deepMergeObjects, weiToHumanReadable } from "@src/utils";
|
|
5
5
|
import {
|
|
@@ -17,11 +17,6 @@ interface Props {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
20
|
-
const getDate = useCallback((blockTimestamp: number) => {
|
|
21
|
-
const date = new Date(blockTimestamp * 1000);
|
|
22
|
-
return format(date, "d MMM yyyy HH:mm:ss");
|
|
23
|
-
}, []);
|
|
24
|
-
|
|
25
20
|
const date = getDate(transaction.timestamp);
|
|
26
21
|
|
|
27
22
|
const supportedTokens: Record<string, Record<string, Token>> = useMemo(() => {
|
|
@@ -80,34 +75,25 @@ export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
|
80
75
|
);
|
|
81
76
|
|
|
82
77
|
return (
|
|
83
|
-
<div className="flex flex-col
|
|
84
|
-
<div className="flex items-center">
|
|
85
|
-
<div className="text-
|
|
86
|
-
<div className="flex
|
|
78
|
+
<div className="flex flex-col globalBorder rounded-xl bg-[rgb(15,15,15)] text-white text-xs sm:text-sm p-4 gap-3 mb-2">
|
|
79
|
+
<div className="flex w-full items-center justify-between">
|
|
80
|
+
<div className="text-sm sm:text-base">{date}</div>
|
|
81
|
+
<div className="flex items-center">
|
|
87
82
|
{transaction.status === "IN_PROGRESS" && (
|
|
88
83
|
<div className="flex items-center">
|
|
89
|
-
<div className="
|
|
90
|
-
<HourGlassIcon />
|
|
91
|
-
</div>
|
|
92
|
-
<div className="text-xs text-[rgb(250,200,100)]">In progress</div>
|
|
84
|
+
<div className="text-[rgb(250,200,100)]">In progress</div>
|
|
93
85
|
</div>
|
|
94
86
|
)}
|
|
95
87
|
|
|
96
88
|
{transaction.status === "DONE" && (
|
|
97
89
|
<div className="flex items-center">
|
|
98
|
-
<div className="
|
|
99
|
-
<CheckIcon />
|
|
100
|
-
</div>
|
|
101
|
-
<div className="text-xs text-[rgb(100,200,100)]">Done</div>
|
|
90
|
+
<div className="text-[rgb(100,200,100)]">Done</div>
|
|
102
91
|
</div>
|
|
103
92
|
)}
|
|
104
93
|
|
|
105
94
|
{transaction.status === "REVERTED" && (
|
|
106
95
|
<div className="flex items-center">
|
|
107
|
-
<div className="
|
|
108
|
-
<XMarkIcon />
|
|
109
|
-
</div>
|
|
110
|
-
<div className="text-xs text-[rgb(255,100,100)]">Reverted</div>
|
|
96
|
+
<div className="text-[rgb(255,100,100)]">Reverted</div>
|
|
111
97
|
</div>
|
|
112
98
|
)}
|
|
113
99
|
|
|
@@ -122,26 +108,24 @@ export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
|
122
108
|
className="ml-2 no-underline"
|
|
123
109
|
aria-label="Show the transaction in the chain explorer"
|
|
124
110
|
>
|
|
125
|
-
<div className="w-3.5 h-3.5
|
|
111
|
+
<div className="w-3.5 h-3.5">
|
|
126
112
|
<ArrowUpRightIcon />
|
|
127
113
|
</div>
|
|
128
114
|
</a>
|
|
129
115
|
</div>
|
|
130
116
|
</div>
|
|
131
|
-
<div className="flex flex-wrap gap-
|
|
132
|
-
<div className="flex
|
|
117
|
+
<div className="flex justify-between flex-wrap gap-2">
|
|
118
|
+
<div className="flex items-center">
|
|
133
119
|
<div className="flex items-center">
|
|
134
120
|
<img
|
|
135
121
|
src={sourceChainData?.image}
|
|
136
122
|
alt={`${sourceChainData?.name} logo`}
|
|
137
123
|
className="w-5 h-5 mr-1"
|
|
138
124
|
/>
|
|
139
|
-
<div
|
|
140
|
-
{sourceChainData?.displayName}
|
|
141
|
-
</div>
|
|
125
|
+
<div>{sourceChainData?.displayName}</div>
|
|
142
126
|
</div>
|
|
143
127
|
|
|
144
|
-
<div className="w-3.5 h-3.5
|
|
128
|
+
<div className="w-3.5 h-3.5 my-0 mx-1.5">
|
|
145
129
|
<ArrowRightIcon />
|
|
146
130
|
</div>
|
|
147
131
|
|
|
@@ -151,20 +135,17 @@ export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
|
151
135
|
alt={`${targetChainData?.name} logo`}
|
|
152
136
|
className="w-5 h-5 mr-1"
|
|
153
137
|
/>
|
|
154
|
-
<div
|
|
155
|
-
{targetChainData?.displayName}
|
|
156
|
-
</div>
|
|
138
|
+
<div>{targetChainData?.displayName}</div>
|
|
157
139
|
</div>
|
|
158
140
|
</div>
|
|
141
|
+
|
|
159
142
|
<div className="flex items-center mb-2 last:mb-0">
|
|
160
|
-
<div className="flex
|
|
143
|
+
<div className="flex items-center flex-wrap">
|
|
161
144
|
<div className="flex items-center">
|
|
162
145
|
{Number(transferredAmount) < MINIMUM_DISPLAYED_TOKEN_AMOUNT
|
|
163
146
|
? `<${MINIMUM_DISPLAYED_TOKEN_AMOUNT}`
|
|
164
147
|
: transferredAmount}
|
|
165
|
-
<div className="
|
|
166
|
-
{tokenData?.symbol}
|
|
167
|
-
</div>
|
|
148
|
+
<div className="ml-1">{tokenData?.symbol}</div>
|
|
168
149
|
{tokenData?.image ? (
|
|
169
150
|
<img
|
|
170
151
|
src={tokenData?.image}
|
|
@@ -179,14 +160,12 @@ export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
|
179
160
|
</div>
|
|
180
161
|
{transaction.tokenOutAddress && (
|
|
181
162
|
<>
|
|
182
|
-
<div className="w-3.5 h-3.5
|
|
163
|
+
<div className="w-3.5 h-3.5 my-0 mx-1.5">
|
|
183
164
|
<ArrowRightIcon />
|
|
184
165
|
</div>
|
|
185
166
|
<div className="flex items-center">
|
|
186
167
|
{Number(receivedAmount) < 0.0001 ? "<0.0001" : receivedAmount}
|
|
187
|
-
<div className="
|
|
188
|
-
{tokenOutData?.symbol}
|
|
189
|
-
</div>
|
|
168
|
+
<div className="ml-1">{tokenOutData?.symbol}</div>
|
|
190
169
|
|
|
191
170
|
{tokenOutData?.image ? (
|
|
192
171
|
<img
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { FC } from "react";
|
|
1
|
+
import React, { FC, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { weiToHumanReadable } from "@src/utils";
|
|
3
|
-
import { Chain, Route, Token } from "@src/models";
|
|
3
|
+
import { Chain, Route, Token, TokenPrices } from "@src/models";
|
|
4
4
|
import { ArrowDownIcon } from "../icons";
|
|
5
|
+
import { UsdPrice } from "@src/components/TxConfigForm/UsdPrice";
|
|
6
|
+
import { getPrices } from "@src/services";
|
|
7
|
+
import { Skeleton } from "@src/components";
|
|
5
8
|
|
|
6
9
|
interface Props {
|
|
7
10
|
isGettingRoute: boolean;
|
|
8
|
-
amount: string;
|
|
9
11
|
route: Route | undefined;
|
|
10
12
|
dstToken: Token | undefined;
|
|
11
13
|
dstChain: Chain | undefined;
|
|
@@ -13,40 +15,67 @@ interface Props {
|
|
|
13
15
|
|
|
14
16
|
export const Summary: FC<Props> = ({
|
|
15
17
|
isGettingRoute,
|
|
16
|
-
amount,
|
|
17
18
|
route,
|
|
18
19
|
dstToken,
|
|
19
20
|
dstChain,
|
|
20
21
|
}) => {
|
|
22
|
+
const [prices, setPrices] = useState<TokenPrices>();
|
|
23
|
+
|
|
24
|
+
const amountReadable = useMemo(
|
|
25
|
+
() =>
|
|
26
|
+
weiToHumanReadable({
|
|
27
|
+
amount: route?.estAmountOut || "0",
|
|
28
|
+
decimals: dstToken?.decimals || 18,
|
|
29
|
+
precisionFractionalPlaces: 5,
|
|
30
|
+
}),
|
|
31
|
+
[route, dstToken],
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (dstChain) {
|
|
36
|
+
getPrices({ chainId: dstChain.chainId, currency: "USD" }).then((prices) =>
|
|
37
|
+
setPrices(prices),
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}, [dstChain]);
|
|
41
|
+
|
|
21
42
|
return (
|
|
22
|
-
<div className="flex
|
|
23
|
-
<div className="flex
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<
|
|
43
|
+
<div className="flex flex-col globalBorder rounded-lg bg-[rgba(15,15,15,1)] p-4 relative">
|
|
44
|
+
<div className="flex justify-between">
|
|
45
|
+
<div className="flex flex-col gap-1">
|
|
46
|
+
<p className="text-[rgba(255,255,255,0.6)] text-sm">You receive</p>
|
|
47
|
+
{isGettingRoute ? (
|
|
48
|
+
<Skeleton
|
|
49
|
+
width="w-[100px]"
|
|
50
|
+
height="h-[36px]"
|
|
51
|
+
other="sm:w-[190px]"
|
|
52
|
+
/>
|
|
53
|
+
) : (
|
|
54
|
+
<div className="flex gap-2 items-center text-white text-xl sm:text-3xl">
|
|
55
|
+
{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>
|
|
36
60
|
</div>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<
|
|
61
|
+
)}
|
|
62
|
+
</div>
|
|
63
|
+
<div className="flex flex-col gap-1 text-sm">
|
|
64
|
+
<p className="text-[rgba(255,255,255,0.6)] text-right">on chain:</p>
|
|
65
|
+
<div className="flex items-center gap-1 text-white">
|
|
66
|
+
<div className="w-4 h-4">
|
|
67
|
+
<img src={dstChain?.image} alt={dstChain?.name} />
|
|
68
|
+
</div>
|
|
69
|
+
<div>{dstChain?.displayName}</div>
|
|
46
70
|
</div>
|
|
47
|
-
<div>{dstChain?.displayName}</div>
|
|
48
71
|
</div>
|
|
49
72
|
</div>
|
|
73
|
+
<UsdPrice
|
|
74
|
+
prices={prices}
|
|
75
|
+
token={dstToken}
|
|
76
|
+
amount={amountReadable}
|
|
77
|
+
loading={isGettingRoute}
|
|
78
|
+
/>
|
|
50
79
|
<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)]">
|
|
51
80
|
<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)] ">
|
|
52
81
|
<ArrowDownIcon />
|
|
@@ -4,10 +4,9 @@ import { DownArrowIcon } from "../icons";
|
|
|
4
4
|
import { Token, Chain, TokenBalances, TokenPrices } from "@src/models";
|
|
5
5
|
import { TokenPicker } from "./TokenPicker";
|
|
6
6
|
import { weiToHumanReadable } from "@src/utils";
|
|
7
|
-
import { Alert } from "../Alert";
|
|
8
7
|
import { ChainListElement } from "./ChainListElement";
|
|
9
8
|
import { BalanceComponent } from "./BalanceComponent";
|
|
10
|
-
import
|
|
9
|
+
import { UsdPrice } from "@src/components/TxConfigForm/UsdPrice";
|
|
11
10
|
|
|
12
11
|
interface Props {
|
|
13
12
|
amount: string;
|
|
@@ -82,10 +81,12 @@ export const SwapPanel: FC<Props> = ({
|
|
|
82
81
|
);
|
|
83
82
|
|
|
84
83
|
return (
|
|
85
|
-
<div className="flex
|
|
86
|
-
<div className="
|
|
87
|
-
<div className="flex flex-col gap-
|
|
88
|
-
<p className="text-white opacity-60 text-sm font-medium">
|
|
84
|
+
<div className="flex justify-between globalBorder rounded-lg bg-[rgba(15,15,15,1)] p-4">
|
|
85
|
+
<div className="flex flex-col justify-between gap-2 overflow-hidden w-1/2">
|
|
86
|
+
<div className="flex flex-col gap-1">
|
|
87
|
+
<p className="text-white opacity-60 text-xs sm:text-sm font-medium">
|
|
88
|
+
You pay
|
|
89
|
+
</p>
|
|
89
90
|
<input
|
|
90
91
|
className="p-0 border-none outline-none bg-transparent text-2xl overflow-ellipsis"
|
|
91
92
|
value={amount}
|
|
@@ -102,80 +103,41 @@ export const SwapPanel: FC<Props> = ({
|
|
|
102
103
|
placeholder="0"
|
|
103
104
|
/>
|
|
104
105
|
</div>
|
|
105
|
-
<div className="flex
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
width="16"
|
|
113
|
-
height="16"
|
|
114
|
-
src={srcChain?.image}
|
|
115
|
-
alt={srcChain?.name}
|
|
116
|
-
/>
|
|
117
|
-
<div>{srcChain?.displayName}</div>
|
|
118
|
-
<DownArrowIcon />
|
|
119
|
-
</div>
|
|
120
|
-
|
|
121
|
-
{chainListShown && (
|
|
122
|
-
<ul
|
|
123
|
-
ref={listRef}
|
|
124
|
-
className="bg-black globalBorder rounded-lg whitespace-nowrap z-1 right-0 top-10 px-2 max-w-full max-h-[40vh] overflow-auto absolute text-sm z-20"
|
|
125
|
-
>
|
|
126
|
-
{chainListOptions.map((chain, index) => (
|
|
127
|
-
<ChainListElement
|
|
128
|
-
index={index}
|
|
129
|
-
length={supportedChains.length}
|
|
130
|
-
setSrcChain={setSrcChain}
|
|
131
|
-
setChainListShown={setChainListShown}
|
|
132
|
-
chain={chain}
|
|
133
|
-
/>
|
|
134
|
-
))}
|
|
135
|
-
</ul>
|
|
136
|
-
)}
|
|
137
|
-
<div
|
|
138
|
-
className="flex gap-2 items-center p-2 max-w-full cursor-pointer bg-black text-white globalBorder rounded-3xl whitespace-nowrap"
|
|
139
|
-
onClick={() => {
|
|
140
|
-
setTokenListShown((state) => !state);
|
|
141
|
-
}}
|
|
142
|
-
>
|
|
143
|
-
<img
|
|
144
|
-
height={16}
|
|
145
|
-
width={16}
|
|
146
|
-
src={srcToken?.image}
|
|
147
|
-
alt={srcToken?.name}
|
|
148
|
-
/>
|
|
149
|
-
<div>{srcToken?.symbol}</div>
|
|
150
|
-
<DownArrowIcon />
|
|
151
|
-
</div>
|
|
152
|
-
|
|
153
|
-
{tokenListShown && (
|
|
154
|
-
<TokenPicker
|
|
155
|
-
onCloseClick={() => setTokenListShown(false)}
|
|
156
|
-
tokens={srcChain?.tokens}
|
|
157
|
-
signer={signer}
|
|
158
|
-
selectedToken={srcToken}
|
|
159
|
-
setSelectedToken={(token) => setSrcToken(token)}
|
|
160
|
-
balances={balances}
|
|
161
|
-
/>
|
|
162
|
-
)}
|
|
106
|
+
<div className="flex items-center text-sm text-[rgba(255,255,255,0.6)]">
|
|
107
|
+
<UsdPrice
|
|
108
|
+
prices={prices}
|
|
109
|
+
token={srcToken}
|
|
110
|
+
amount={amount}
|
|
111
|
+
loading={false}
|
|
112
|
+
/>
|
|
163
113
|
</div>
|
|
164
114
|
</div>
|
|
115
|
+
<div className="flex flex-col relative items-end gap-2.5 w-1/2 text-xs">
|
|
116
|
+
<div
|
|
117
|
+
className="flex gap-2 items-center p-2 max-w-full cursor-pointer bg-black text-white globalBorder rounded-3xl whitespace-nowrap"
|
|
118
|
+
onClick={() => {
|
|
119
|
+
setTokenListShown((state) => !state);
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
<img
|
|
123
|
+
height={16}
|
|
124
|
+
width={16}
|
|
125
|
+
src={srcToken?.image}
|
|
126
|
+
alt={srcToken?.name}
|
|
127
|
+
/>
|
|
128
|
+
<div>{srcToken?.symbol}</div>
|
|
129
|
+
<DownArrowIcon />
|
|
130
|
+
</div>
|
|
165
131
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
<Alert desc="Unknown price" />
|
|
176
|
-
)
|
|
177
|
-
) : (
|
|
178
|
-
<>$0.00</>
|
|
132
|
+
{tokenListShown && (
|
|
133
|
+
<TokenPicker
|
|
134
|
+
onCloseClick={() => setTokenListShown(false)}
|
|
135
|
+
tokens={srcChain?.tokens}
|
|
136
|
+
signer={signer}
|
|
137
|
+
selectedToken={srcToken}
|
|
138
|
+
setSelectedToken={(token) => setSrcToken(token)}
|
|
139
|
+
balances={balances}
|
|
140
|
+
/>
|
|
179
141
|
)}
|
|
180
142
|
<div
|
|
181
143
|
onClick={handleMaxClick}
|
|
@@ -185,6 +147,37 @@ export const SwapPanel: FC<Props> = ({
|
|
|
185
147
|
<BalanceComponent balances={balances} srcToken={srcToken} />
|
|
186
148
|
)}
|
|
187
149
|
</div>
|
|
150
|
+
<div
|
|
151
|
+
ref={buttonRef}
|
|
152
|
+
className="bg-black globalBorder rounded-2xl whitespace-nowrap flex items-center p-2 cursor-pointer gap-2"
|
|
153
|
+
onClick={() => setChainListShown((prev) => !prev)}
|
|
154
|
+
>
|
|
155
|
+
<img
|
|
156
|
+
width="16"
|
|
157
|
+
height="16"
|
|
158
|
+
src={srcChain?.image}
|
|
159
|
+
alt={srcChain?.name}
|
|
160
|
+
/>
|
|
161
|
+
<div>{srcChain?.displayName}</div>
|
|
162
|
+
<DownArrowIcon />
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
{chainListShown && (
|
|
166
|
+
<ul
|
|
167
|
+
ref={listRef}
|
|
168
|
+
className="bg-black globalBorder rounded-lg whitespace-nowrap z-1 right-0 top-10 px-2 max-w-full max-h-[40vh] overflow-auto absolute text-sm z-20"
|
|
169
|
+
>
|
|
170
|
+
{chainListOptions.map((chain, index) => (
|
|
171
|
+
<ChainListElement
|
|
172
|
+
index={index}
|
|
173
|
+
length={supportedChains.length}
|
|
174
|
+
setSrcChain={setSrcChain}
|
|
175
|
+
setChainListShown={setChainListShown}
|
|
176
|
+
chain={chain}
|
|
177
|
+
/>
|
|
178
|
+
))}
|
|
179
|
+
</ul>
|
|
180
|
+
)}
|
|
188
181
|
</div>
|
|
189
182
|
</div>
|
|
190
183
|
);
|
|
@@ -24,7 +24,7 @@ export const TokenPicker: FC<Props> = ({
|
|
|
24
24
|
}) => {
|
|
25
25
|
const [searchValue, setSearchValue] = useState("");
|
|
26
26
|
|
|
27
|
-
const modalRoot = document.querySelector("
|
|
27
|
+
const modalRoot = document.querySelector("#xswap-modal");
|
|
28
28
|
|
|
29
29
|
const onBackdropClick = (e: MouseEvent<HTMLDivElement>) => {
|
|
30
30
|
e.stopPropagation();
|
|
@@ -153,7 +153,7 @@ export const TokenPicker: FC<Props> = ({
|
|
|
153
153
|
})}
|
|
154
154
|
</div>
|
|
155
155
|
) : (
|
|
156
|
-
<Skeleton
|
|
156
|
+
<Skeleton width="w-12" height="h-3" />
|
|
157
157
|
)}
|
|
158
158
|
</>
|
|
159
159
|
)}
|
|
@@ -16,8 +16,8 @@ export const TopBar: FC<Props> = ({
|
|
|
16
16
|
historyTabShown,
|
|
17
17
|
}) => {
|
|
18
18
|
return (
|
|
19
|
-
<div className="flex w-full justify-between mx-auto pl-4 pr-8 pt-2">
|
|
20
|
-
<div className="rounded-lg text-[rgba(255,255,255,0.6)] text-base whitespace-nowrap">
|
|
19
|
+
<div className="flex w-full justify-between items-center mx-auto sm:pl-4 pr-8 pt-2">
|
|
20
|
+
<div className="rounded-lg text-[rgba(255,255,255,0.6)] text-xs sm:text-base whitespace-nowrap">
|
|
21
21
|
{signer
|
|
22
22
|
? `Connected wallet: ${shortAddress(signer)}`
|
|
23
23
|
: `Wallet disconnected`}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Alert, Skeleton } from "@src/components";
|
|
2
|
+
import { Token, TokenPrices } from "@src/models";
|
|
3
|
+
import { FC, useEffect, useMemo, useState } from "react";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
prices: TokenPrices | undefined;
|
|
7
|
+
token: Token | undefined;
|
|
8
|
+
amount: string | undefined;
|
|
9
|
+
loading: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const UsdPrice: FC<Props> = ({
|
|
13
|
+
prices,
|
|
14
|
+
token,
|
|
15
|
+
amount = "0",
|
|
16
|
+
loading = false,
|
|
17
|
+
}) => {
|
|
18
|
+
const [usdPrice, setUsdPrice] = useState<string>("0.00");
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (token && prices && prices[token.address]) {
|
|
22
|
+
setUsdPrice((Number(amount) * Number(prices[token.address])).toFixed(2));
|
|
23
|
+
}
|
|
24
|
+
}, [token, prices, amount]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="opacity-60 py-4">
|
|
28
|
+
{loading ? (
|
|
29
|
+
<Skeleton width="w-12" height="h-4" />
|
|
30
|
+
) : token ? (
|
|
31
|
+
prices && prices[token.address] ? (
|
|
32
|
+
<div>{`$${usdPrice}`}</div>
|
|
33
|
+
) : (
|
|
34
|
+
<Alert desc="Unknown price" />
|
|
35
|
+
)
|
|
36
|
+
) : (
|
|
37
|
+
<>$0.00</>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
@@ -114,8 +114,7 @@ export const openTxConfigForm = async ({
|
|
|
114
114
|
let txConfigFormRoot: Root;
|
|
115
115
|
if (typeof document !== "undefined") {
|
|
116
116
|
const xswapElement = document.createElement("div");
|
|
117
|
-
xswapElement.setAttribute("id", "
|
|
118
|
-
xswapElement.classList.add("xswap");
|
|
117
|
+
xswapElement.setAttribute("id", "xswap-modal");
|
|
119
118
|
document.body.appendChild(xswapElement);
|
|
120
119
|
txConfigFormRoot = createRoot(xswapElement);
|
|
121
120
|
}
|