@xswap-link/sdk 0.13.0 → 0.14.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 +15 -0
- package/dist/index.d.mts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.global.js +90 -89
- package/dist/index.js +1633 -1519
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1597 -1480
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/assets/icons/AdjustmentsIcon.tsx +18 -0
- package/src/assets/icons/CaretDownIcon.tsx +12 -0
- package/src/assets/icons/CaretsUpDownIcon.tsx +13 -0
- package/src/assets/icons/ChainlinkMarkIcon.tsx +17 -0
- package/src/assets/icons/ClockIcon.tsx +18 -0
- package/src/assets/icons/WarningIcon.tsx +16 -0
- package/src/assets/icons/index.ts +6 -0
- package/src/components/Modal/index.tsx +2 -2
- package/src/components/PoweredBy/index.tsx +14 -5
- package/src/components/Swap/Header/Controls/index.tsx +50 -36
- package/src/components/Swap/Header/index.tsx +12 -5
- package/src/components/Swap/HistoryView/ActivityCard/index.tsx +212 -0
- package/src/components/Swap/HistoryView/index.tsx +24 -6
- package/src/components/Swap/ReorderButton/ReorderButton.tsx +5 -7
- package/src/components/Swap/SettingsView/Delivery/index.tsx +27 -28
- package/src/components/Swap/SettingsView/InfiniteApproval/index.tsx +27 -24
- package/src/components/Swap/SettingsView/Slippage/index.tsx +44 -43
- package/src/components/Swap/SettingsView/index.tsx +1 -1
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +2 -2
- package/src/components/Swap/SwapView/FeesPanel/DeliveryInfo/index.tsx +9 -19
- package/src/components/Swap/SwapView/FeesPanel/Fee/index.tsx +4 -4
- package/src/components/Swap/SwapView/FeesPanel/Fees/index.tsx +5 -9
- package/src/components/Swap/SwapView/FeesPanel/index.tsx +21 -22
- package/src/components/Swap/SwapView/SwapButton/index.tsx +25 -6
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/Balance/index.tsx +56 -12
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +42 -41
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/NetworkFilter/index.tsx +157 -0
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +98 -55
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +160 -239
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +57 -31
- package/src/components/Swap/SwapView/SwapPanel/UsdValue/index.tsx +27 -0
- package/src/components/Swap/SwapView/SwapPanel/WalletPanel/index.tsx +60 -49
- package/src/components/Swap/SwapView/SwapPanel/index.tsx +20 -25
- package/src/components/Swap/SwapView/WalletPicker/index.tsx +6 -1
- package/src/components/Swap/SwapView/index.tsx +2 -1
- package/src/components/Swap/index.tsx +4 -2
- package/src/components/ToggleButton/index.tsx +18 -15
- package/src/components/TxConfigForm/index.tsx +5 -5
- package/src/components/TxWidgetWC/index.tsx +4 -0
- package/src/components/TxWidgetWCWrapped/index.tsx +2 -0
- package/src/context/HistoryProvider.tsx +1 -0
- package/src/context/SwapProvider.tsx +94 -67
- package/src/models/TransactionHistory.ts +1 -0
- package/src/models/payloads/ModalIntegrationPayload.ts +1 -0
- package/src/models/payloads/WidgetIntegrationPayload.ts +1 -0
- package/src/utils/index.ts +21 -0
- package/tailwind.config.js +2 -2
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +0 -97
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +0 -103
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +0 -65
- package/src/components/Swap/SwapView/SwapPanel/MaxPanel/index.tsx +0 -43
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx +0 -37
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SafeInput, Skeleton } from "@src/components";
|
|
2
2
|
import { NUMBER_INPUT_REGEX } from "@src/constants";
|
|
3
3
|
import { useSwapContext } from "@src/context";
|
|
4
|
+
import { weiToHumanReadable } from "@src/utils";
|
|
4
5
|
import { useMemo } from "react";
|
|
5
6
|
import { SwapPanelType } from "../../../SwapView";
|
|
6
|
-
import { Balance } from "./Balance";
|
|
7
7
|
import { Ecosystem } from "@src/models";
|
|
8
8
|
|
|
9
9
|
type Props = {
|
|
@@ -14,16 +14,29 @@ export const AmountPanel = ({ type }: Props) => {
|
|
|
14
14
|
const {
|
|
15
15
|
srcChain,
|
|
16
16
|
srcValue,
|
|
17
|
-
|
|
17
|
+
srcToken,
|
|
18
|
+
srcTokenBalanceWei,
|
|
18
19
|
dstToken,
|
|
19
20
|
dstChain,
|
|
20
21
|
dstValue,
|
|
21
|
-
dstValueUsd,
|
|
22
22
|
setSrcValue,
|
|
23
23
|
isFetchingRoute,
|
|
24
24
|
bridgeUI,
|
|
25
25
|
} = useSwapContext();
|
|
26
26
|
|
|
27
|
+
const onMaxClick = () => {
|
|
28
|
+
if (!srcTokenBalanceWei) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
setSrcValue(
|
|
32
|
+
weiToHumanReadable({
|
|
33
|
+
amount: srcTokenBalanceWei,
|
|
34
|
+
decimals: srcToken?.decimals || 18,
|
|
35
|
+
precisionFractionalPlaces: srcToken?.decimals || 18,
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
27
40
|
const value = useMemo(() => {
|
|
28
41
|
if (
|
|
29
42
|
type === "destination" &&
|
|
@@ -45,46 +58,34 @@ export const AmountPanel = ({ type }: Props) => {
|
|
|
45
58
|
dstChain,
|
|
46
59
|
]);
|
|
47
60
|
|
|
48
|
-
const valueUsd = useMemo(
|
|
49
|
-
() => (type === "source" ? srcValueUsd : dstValueUsd),
|
|
50
|
-
[dstValueUsd, srcValueUsd, type],
|
|
51
|
-
);
|
|
52
|
-
|
|
53
61
|
return (
|
|
54
|
-
<div className="flex
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
) : isFetchingRoute ? (
|
|
70
|
-
<div className="flex flex-col gap-1">
|
|
71
|
-
<Skeleton className="w-[150px] h-[30px]" />
|
|
72
|
-
<Skeleton className="w-[100px] h-[20px]" />
|
|
73
|
-
</div>
|
|
74
|
-
) : (
|
|
75
|
-
<>
|
|
76
|
-
<div
|
|
77
|
-
className={`text-xl text-t_text_secondary font-sans-bold font-bold`}
|
|
62
|
+
<div className="flex items-center gap-3 flex-1 min-w-0 overflow-hidden text-left">
|
|
63
|
+
{type === "source" ? (
|
|
64
|
+
<>
|
|
65
|
+
<SafeInput
|
|
66
|
+
id="swap-amount-input"
|
|
67
|
+
className="bg-transparent border-none p-0 text-2xl leading-8 outline-none w-full min-w-0 text-t_text_primary placeholder:text-t_text_primary placeholder:text-opacity-40"
|
|
68
|
+
regex={NUMBER_INPUT_REGEX}
|
|
69
|
+
value={srcValue}
|
|
70
|
+
onChange={(value) => setSrcValue(value)}
|
|
71
|
+
/>
|
|
72
|
+
{!!srcTokenBalanceWei && (
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
onClick={onMaxClick}
|
|
76
|
+
className="shrink-0 px-2.5 py-1 rounded-full border border-solid border-t_main_accent_light bg-gradient-to-r from-t_main_accent_light/25 to-t_main_accent_dark/25 text-[10px] font-medium leading-[18px] tracking-[0.08em] text-t_text_primary hover:from-t_main_accent_light/40 hover:to-t_main_accent_dark/40 transition-colors"
|
|
78
77
|
>
|
|
79
|
-
|
|
80
|
-
</
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
MAX
|
|
79
|
+
</button>
|
|
80
|
+
)}
|
|
81
|
+
</>
|
|
82
|
+
) : isFetchingRoute ? (
|
|
83
|
+
<Skeleton className="w-[150px] h-[32px]" />
|
|
84
|
+
) : (
|
|
85
|
+
<div className="text-2xl leading-8 text-t_text_primary opacity-60 truncate">
|
|
86
|
+
{value || 0}
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
88
89
|
</div>
|
|
89
90
|
);
|
|
90
91
|
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { ChevronDownIcon, SearchIcon } from "@src/assets/icons";
|
|
2
|
+
import { useSwapContext } from "@src/context";
|
|
3
|
+
import { SwapPanelType } from "@src/components/Swap/SwapView";
|
|
4
|
+
import { Chain } from "@src/models";
|
|
5
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import { Virtuoso } from "react-virtuoso";
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
type: SwapPanelType;
|
|
10
|
+
selectedChain: Chain | undefined;
|
|
11
|
+
onSelect: (chain: Chain | undefined) => void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Network filter embedded in the token picker search bar.
|
|
16
|
+
* Selecting a network only narrows the token list — the swap chain is
|
|
17
|
+
* set when a token gets picked.
|
|
18
|
+
*/
|
|
19
|
+
export const NetworkFilter = ({ type, selectedChain, onSelect }: Props) => {
|
|
20
|
+
const { srcChainOptions, dstChainOptions } = useSwapContext();
|
|
21
|
+
const [open, setOpen] = useState(false);
|
|
22
|
+
const [searchValue, setSearchValue] = useState("");
|
|
23
|
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
24
|
+
|
|
25
|
+
const chains = useMemo(
|
|
26
|
+
() => (type === "source" ? srcChainOptions : dstChainOptions),
|
|
27
|
+
[type, srcChainOptions, dstChainOptions],
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const filteredChains = useMemo(() => {
|
|
31
|
+
if (!searchValue) return chains;
|
|
32
|
+
const searchLower = searchValue.toLowerCase();
|
|
33
|
+
return chains.filter(
|
|
34
|
+
(chain) =>
|
|
35
|
+
chain.displayName.toLowerCase().includes(searchLower) ||
|
|
36
|
+
chain.chainId.toLowerCase().includes(searchLower),
|
|
37
|
+
);
|
|
38
|
+
}, [chains, searchValue]);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (!open) {
|
|
42
|
+
setSearchValue("");
|
|
43
|
+
}
|
|
44
|
+
}, [open]);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const onPointerDown = (e: Event) => {
|
|
48
|
+
if (
|
|
49
|
+
containerRef.current &&
|
|
50
|
+
!e.composedPath().includes(containerRef.current)
|
|
51
|
+
) {
|
|
52
|
+
setOpen(false);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
document.addEventListener("mousedown", onPointerDown);
|
|
56
|
+
return () => document.removeEventListener("mousedown", onPointerDown);
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
const previewChains = chains.slice(0, 4);
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className="relative" ref={containerRef}>
|
|
63
|
+
<button
|
|
64
|
+
type="button"
|
|
65
|
+
onClick={() => setOpen((state) => !state)}
|
|
66
|
+
className="flex items-center gap-2 h-12 px-3 py-2 rounded-lg bg-t_bg_tertiary bg-opacity-[0.04] hover:bg-opacity-10 transition-colors"
|
|
67
|
+
>
|
|
68
|
+
{selectedChain ? (
|
|
69
|
+
<img
|
|
70
|
+
src={selectedChain.image}
|
|
71
|
+
alt={selectedChain.displayName}
|
|
72
|
+
className="w-5 h-5 rounded-full"
|
|
73
|
+
/>
|
|
74
|
+
) : (
|
|
75
|
+
<div className="grid grid-cols-2 gap-0.5 w-6 shrink-0">
|
|
76
|
+
{previewChains.map((chain) => (
|
|
77
|
+
<img
|
|
78
|
+
key={chain.chainId}
|
|
79
|
+
src={chain.image}
|
|
80
|
+
alt={chain.displayName}
|
|
81
|
+
className="w-[11px] h-[11px] rounded-full"
|
|
82
|
+
/>
|
|
83
|
+
))}
|
|
84
|
+
</div>
|
|
85
|
+
)}
|
|
86
|
+
<p className="text-sm leading-6 tracking-[0.01em] text-t_text_primary whitespace-nowrap max-w-[120px] truncate">
|
|
87
|
+
{selectedChain ? selectedChain.displayName : "All Networks"}
|
|
88
|
+
</p>
|
|
89
|
+
<div
|
|
90
|
+
className={`flex items-center justify-center w-6 h-6 fill-t_text_primary opacity-50 transition-transform [&_svg]:w-3 [&_svg]:h-3 ${
|
|
91
|
+
open ? "rotate-180" : ""
|
|
92
|
+
}`}
|
|
93
|
+
>
|
|
94
|
+
<ChevronDownIcon />
|
|
95
|
+
</div>
|
|
96
|
+
</button>
|
|
97
|
+
|
|
98
|
+
{open && (
|
|
99
|
+
<div className="absolute right-0 top-[calc(100%+8px)] z-20 flex flex-col w-[220px] max-h-[280px] rounded-xl bg-t_bg_primary border border-solid border-t_text_primary border-opacity-10 backdrop-blur-[24px] overflow-hidden shadow-lg">
|
|
100
|
+
<div className="flex items-center gap-2 px-4 py-3 border-b border-solid border-t_text_primary border-opacity-10">
|
|
101
|
+
<div className="fill-t_text_primary opacity-50 [&_svg]:w-3.5 [&_svg]:h-3.5 flex items-center">
|
|
102
|
+
<SearchIcon />
|
|
103
|
+
</div>
|
|
104
|
+
<input
|
|
105
|
+
value={searchValue}
|
|
106
|
+
onChange={(e) => setSearchValue(e.target.value)}
|
|
107
|
+
placeholder={`Browse ${chains.length} Chains...`}
|
|
108
|
+
className="bg-transparent border-none outline-none w-full text-sm text-t_text_primary placeholder:text-t_text_primary placeholder:text-opacity-40"
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
<div className="h-[200px]">
|
|
112
|
+
<Virtuoso
|
|
113
|
+
style={{ height: "200px" }}
|
|
114
|
+
data={[undefined, ...filteredChains] as (Chain | undefined)[]}
|
|
115
|
+
itemContent={(_, chain) => (
|
|
116
|
+
<button
|
|
117
|
+
type="button"
|
|
118
|
+
onClick={() => {
|
|
119
|
+
onSelect(chain);
|
|
120
|
+
setOpen(false);
|
|
121
|
+
}}
|
|
122
|
+
className={`flex items-center gap-2 w-full px-4 py-2 text-left hover:bg-t_bg_tertiary hover:bg-opacity-10 transition-colors ${
|
|
123
|
+
(chain?.chainId || "") === (selectedChain?.chainId || "")
|
|
124
|
+
? "bg-t_bg_tertiary bg-opacity-10"
|
|
125
|
+
: ""
|
|
126
|
+
}`}
|
|
127
|
+
>
|
|
128
|
+
{chain ? (
|
|
129
|
+
<img
|
|
130
|
+
src={chain.image}
|
|
131
|
+
alt={chain.displayName}
|
|
132
|
+
className="w-5 h-5 rounded-full"
|
|
133
|
+
/>
|
|
134
|
+
) : (
|
|
135
|
+
<div className="grid grid-cols-2 gap-px w-5 shrink-0">
|
|
136
|
+
{previewChains.map((previewChain) => (
|
|
137
|
+
<img
|
|
138
|
+
key={previewChain.chainId}
|
|
139
|
+
src={previewChain.image}
|
|
140
|
+
alt={previewChain.displayName}
|
|
141
|
+
className="w-[9px] h-[9px] rounded-full"
|
|
142
|
+
/>
|
|
143
|
+
))}
|
|
144
|
+
</div>
|
|
145
|
+
)}
|
|
146
|
+
<p className="text-sm leading-6 text-t_text_primary truncate">
|
|
147
|
+
{chain ? chain.displayName : "All Networks"}
|
|
148
|
+
</p>
|
|
149
|
+
</button>
|
|
150
|
+
)}
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
)}
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { StarsIcon } from "@src/assets/icons";
|
|
1
|
+
import { StarsIcon, WarningIcon } from "@src/assets/icons";
|
|
2
2
|
import { Skeleton, TokenLogoWithChain } from "@src/components";
|
|
3
3
|
import { SwapPanelType } from "@src/components/Swap/SwapView";
|
|
4
4
|
import { useSwapContext } from "@src/context";
|
|
5
5
|
import { TokenOption } from "@src/models";
|
|
6
|
-
import { weiToHumanReadable } from "@src/utils";
|
|
6
|
+
import { shortAddress, weiToHumanReadable } from "@src/utils";
|
|
7
7
|
import { ethers } from "ethers";
|
|
8
8
|
import { useMemo } from "react";
|
|
9
9
|
import { useAccount } from "wagmi";
|
|
@@ -14,6 +14,11 @@ type Props = {
|
|
|
14
14
|
selectedChainId: string | undefined;
|
|
15
15
|
onClick: () => void;
|
|
16
16
|
panelType: SwapPanelType;
|
|
17
|
+
/**
|
|
18
|
+
* When picking this token would disconnect the other side of the swap,
|
|
19
|
+
* names the side that will be reset ("source" | "destination").
|
|
20
|
+
*/
|
|
21
|
+
resetWarning?: SwapPanelType | null;
|
|
17
22
|
};
|
|
18
23
|
export const TokenItem = ({
|
|
19
24
|
token,
|
|
@@ -21,6 +26,7 @@ export const TokenItem = ({
|
|
|
21
26
|
onClick,
|
|
22
27
|
selectedChainId,
|
|
23
28
|
panelType,
|
|
29
|
+
resetWarning,
|
|
24
30
|
}: Props) => {
|
|
25
31
|
const {
|
|
26
32
|
supportedChains,
|
|
@@ -55,66 +61,103 @@ export const TokenItem = ({
|
|
|
55
61
|
return tokenBalance * +tokenPrice;
|
|
56
62
|
}, [tokenBalance, tokenPrice, hasBalance]);
|
|
57
63
|
|
|
64
|
+
const isSelected =
|
|
65
|
+
token.address.toLowerCase() === selectedTokenAddress?.toLowerCase() &&
|
|
66
|
+
selectedChainId &&
|
|
67
|
+
token.chainId === selectedChainId;
|
|
68
|
+
|
|
58
69
|
return (
|
|
59
|
-
<div
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
70
|
+
<div className="pb-2">
|
|
71
|
+
<div
|
|
72
|
+
className={`flex gap-3 items-center p-3 sm:p-4 rounded-xl cursor-pointer bg-gradient-to-r from-t_bg_tertiary/[0.02] to-t_bg_tertiary/[0.02] bg-t_bg_secondary bg-opacity-15 hover:bg-t_bg_tertiary hover:bg-opacity-10 transition-colors ${
|
|
73
|
+
isSelected ? "!bg-t_bg_tertiary !bg-opacity-10" : ""
|
|
74
|
+
}`}
|
|
75
|
+
onClick={onClick}
|
|
76
|
+
>
|
|
77
|
+
<div className={`shrink-0 ${resetWarning ? "opacity-40" : ""}`}>
|
|
78
|
+
<TokenLogoWithChain
|
|
79
|
+
token={token}
|
|
80
|
+
chain={chain}
|
|
81
|
+
tokenLogoClassName="min-w-10 w-10 h-10"
|
|
82
|
+
generatedLogoClassName="min-w-10 w-10 h-10 text-[16px]"
|
|
83
|
+
chainLogoClassName="w-[18px]"
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
<div className="flex justify-between items-center gap-2 w-full min-w-0">
|
|
87
|
+
<div
|
|
88
|
+
className={`text-left min-w-0 ${resetWarning ? "opacity-40" : ""}`}
|
|
89
|
+
>
|
|
90
|
+
<div className="text-sm font-medium leading-5 tracking-[0.01em] text-t_text_primary flex items-center gap-1">
|
|
91
|
+
{token.symbol}
|
|
92
|
+
{integrationConfig?.highlightedDstTokens?.includes(
|
|
93
|
+
token.symbol,
|
|
94
|
+
) &&
|
|
95
|
+
panelType === "destination" && (
|
|
96
|
+
<div
|
|
97
|
+
className="flex items-center justify-center text-t_text_primary rounded-full w-3.5 h-3.5 text-xs"
|
|
98
|
+
title="AI-powered token"
|
|
99
|
+
>
|
|
100
|
+
<StarsIcon />
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
<div className="flex gap-2 items-center text-xs leading-[18px] tracking-[0.01em] text-t_text_primary text-opacity-50">
|
|
105
|
+
<span className="whitespace-nowrap">
|
|
106
|
+
{chain?.displayName || token.name}
|
|
107
|
+
</span>
|
|
108
|
+
{!resetWarning && (
|
|
109
|
+
<>
|
|
110
|
+
<span className="w-0.5 h-0.5 bg-t_text_primary opacity-25 shrink-0" />
|
|
111
|
+
<span className="whitespace-nowrap hidden sm:block">
|
|
112
|
+
{shortAddress(token.address)}
|
|
113
|
+
</span>
|
|
114
|
+
</>
|
|
115
|
+
)}
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<div className="text-right shrink-0">
|
|
120
|
+
{address && isFetchingBalances ? (
|
|
121
|
+
<Skeleton className="w-[48px] h-[12px]" />
|
|
122
|
+
) : (
|
|
123
|
+
token.balance &&
|
|
124
|
+
token.decimals &&
|
|
125
|
+
address && (
|
|
82
126
|
<div
|
|
83
|
-
className={`
|
|
84
|
-
|
|
127
|
+
className={`text-sm font-medium leading-5 tracking-[0.01em] text-t_text_primary ${
|
|
128
|
+
resetWarning ? "opacity-40" : ""
|
|
129
|
+
}`}
|
|
85
130
|
>
|
|
86
|
-
|
|
131
|
+
{token.balance.eq(0) || tokenBalance! > 0.0001
|
|
132
|
+
? weiToHumanReadable({
|
|
133
|
+
amount: token.balance.toString(),
|
|
134
|
+
decimals: token.decimals,
|
|
135
|
+
precisionFractionalPlaces: 4,
|
|
136
|
+
})
|
|
137
|
+
: "<0.0001"}
|
|
87
138
|
</div>
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
? weiToHumanReadable({
|
|
99
|
-
amount: token.balance.toString(),
|
|
100
|
-
decimals: token.decimals,
|
|
101
|
-
precisionFractionalPlaces: 4,
|
|
102
|
-
})
|
|
103
|
-
: "<0.0001"}
|
|
104
|
-
</div>
|
|
105
|
-
{hasBalance && (
|
|
106
|
-
<div className="text-xs text-t_text_primary text-opacity-50">
|
|
107
|
-
{tokenValueUsd ? `$${tokenValueUsd.toFixed(2)}` : "$ -"}
|
|
139
|
+
)
|
|
140
|
+
)}
|
|
141
|
+
{resetWarning ? (
|
|
142
|
+
<div className="flex items-center justify-end gap-1.5 text-[#D77F02]">
|
|
143
|
+
<WarningIcon className="w-3.5 h-3.5 shrink-0" />
|
|
144
|
+
<span className="text-xs leading-[18px] tracking-[0.01em] whitespace-nowrap">
|
|
145
|
+
{resetWarning === "source"
|
|
146
|
+
? "Source will reset after selection."
|
|
147
|
+
: "Destination will reset after selection."}
|
|
148
|
+
</span>
|
|
108
149
|
</div>
|
|
150
|
+
) : (
|
|
151
|
+
!isFetchingBalances &&
|
|
152
|
+
hasBalance &&
|
|
153
|
+
address && (
|
|
154
|
+
<div className="text-xs leading-[18px] tracking-[0.01em] text-t_text_primary text-opacity-50">
|
|
155
|
+
{tokenValueUsd ? `${tokenValueUsd.toFixed(2)} USD` : "-"}
|
|
156
|
+
</div>
|
|
157
|
+
)
|
|
109
158
|
)}
|
|
110
159
|
</div>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
{address && isFetchingBalances && (
|
|
114
|
-
<div>
|
|
115
|
-
<Skeleton className="w-[48px] h-[12px]" />
|
|
116
|
-
</div>
|
|
117
|
-
)}
|
|
160
|
+
</div>
|
|
118
161
|
</div>
|
|
119
162
|
</div>
|
|
120
163
|
);
|