@xswap-link/sdk 0.9.0 → 0.9.1
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 +6 -0
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.global.js +118 -118
- package/dist/index.js +7 -7
- package/dist/index.mjs +9 -9
- package/package.json +1 -1
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +51 -59
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +36 -11
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +26 -6
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +5 -1
- package/src/components/Swap/SwapView/SwapPanel/index.tsx +1 -1
- package/src/components/Swap/SwapView/index.tsx +2 -2
- package/src/components/Tooltip/index.tsx +1 -1
- package/src/context/SwapProvider.tsx +27 -38
- package/src/models/TokenData.ts +3 -1
- package/src/models/payloads/GetPricesPayload.ts +1 -1
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { DotGreenIcon
|
|
1
|
+
import { DotGreenIcon } from "@src/assets/icons";
|
|
2
2
|
import { SwapPanelType } from "@src/components/Swap/SwapView";
|
|
3
|
-
import { Tooltip } from "@src/components/Tooltip";
|
|
4
3
|
import { useSwapContext } from "@src/context";
|
|
5
4
|
import useNetworks from "@src/hooks/networkManagement/useNetworks";
|
|
6
5
|
import { Chain } from "@src/models";
|
|
7
|
-
import { useMemo
|
|
6
|
+
import { useMemo } from "react";
|
|
8
7
|
|
|
9
8
|
type Props = {
|
|
10
9
|
chain: Chain;
|
|
@@ -18,8 +17,6 @@ export const ChainItem = ({ chain, type, onClick, disabled }: Props) => {
|
|
|
18
17
|
networks: { evm },
|
|
19
18
|
} = useNetworks();
|
|
20
19
|
|
|
21
|
-
const tooltipTriggerRef = useRef<SVGSVGElement>(null);
|
|
22
|
-
|
|
23
20
|
const { srcChain, dstChain, bridgeUI } = useSwapContext();
|
|
24
21
|
|
|
25
22
|
const currentChainId = useMemo(
|
|
@@ -40,66 +37,61 @@ export const ChainItem = ({ chain, type, onClick, disabled }: Props) => {
|
|
|
40
37
|
return type === "destination" ? srcChain?.chainId : dstChain?.chainId;
|
|
41
38
|
}, [bridgeUI, dstChain?.chainId, srcChain?.chainId, type]);
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
: ""
|
|
57
|
-
}`}
|
|
58
|
-
>
|
|
59
|
-
<div className="flex gap-3 items-center w-full">
|
|
60
|
-
<img src={chain.image} alt={chain.name} className="w-[34px] h-[34px]" />
|
|
61
|
-
<p>{chain.displayName}</p>
|
|
62
|
-
</div>
|
|
40
|
+
const getTooltipText = () => {
|
|
41
|
+
if (chain.chainId === sameChainId) {
|
|
42
|
+
return "Transfers between the same chains are not available";
|
|
43
|
+
}
|
|
44
|
+
if (disabled) {
|
|
45
|
+
return bridgeUI
|
|
46
|
+
? "Token is not available on this chain"
|
|
47
|
+
: `Swap from ${
|
|
48
|
+
srcChain?.displayName || "the source chain"
|
|
49
|
+
} to this chain is currently not supported.`;
|
|
50
|
+
}
|
|
51
|
+
return "";
|
|
52
|
+
};
|
|
63
53
|
|
|
64
|
-
|
|
65
|
-
<div className="flex items-baseline gap-1">
|
|
66
|
-
<DotGreenIcon />
|
|
67
|
-
<div className="text-t_text_green">connected</div>
|
|
68
|
-
</div>
|
|
69
|
-
)}
|
|
54
|
+
const tooltipText = getTooltipText();
|
|
70
55
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
56
|
+
return (
|
|
57
|
+
<div className="group relative">
|
|
58
|
+
<div
|
|
59
|
+
onClick={() => {
|
|
60
|
+
if (chain.chainId === sameChainId || disabled) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
onClick(chain.chainId);
|
|
64
|
+
}}
|
|
65
|
+
className={`flex justify-between items-center gap-2 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-chain-item ${
|
|
66
|
+
currentChainId === chain.chainId ? "selected-chain-item" : ""
|
|
67
|
+
} ${
|
|
68
|
+
chain.chainId === sameChainId || disabled
|
|
69
|
+
? "disabled-chain-item cursor-default"
|
|
70
|
+
: ""
|
|
71
|
+
}`}
|
|
72
|
+
>
|
|
73
|
+
<div className="flex gap-3 items-center w-full">
|
|
74
|
+
<img
|
|
75
|
+
src={chain.image}
|
|
76
|
+
alt={chain.name}
|
|
77
|
+
className="w-[34px] h-[34px]"
|
|
84
78
|
/>
|
|
79
|
+
<p>{chain.displayName}</p>
|
|
85
80
|
</div>
|
|
86
|
-
)}
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
position="BOTTOM"
|
|
94
|
-
triggerRef={tooltipTriggerRef}
|
|
95
|
-
/>
|
|
96
|
-
</div>
|
|
97
|
-
)}
|
|
82
|
+
{tooltipText && (
|
|
83
|
+
<div className="w-full text-center opacity-0 group-hover:opacity-100 text-xs transition-opacity duration-200">
|
|
84
|
+
{tooltipText}
|
|
85
|
+
</div>
|
|
86
|
+
)}
|
|
98
87
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
88
|
+
{connected && (
|
|
89
|
+
<div className="flex items-baseline gap-1">
|
|
90
|
+
<DotGreenIcon />
|
|
91
|
+
<div className="text-t_text_green">connected</div>
|
|
92
|
+
</div>
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
103
95
|
</div>
|
|
104
96
|
);
|
|
105
97
|
};
|
|
@@ -18,7 +18,7 @@ export const TokenItem = ({
|
|
|
18
18
|
onClick,
|
|
19
19
|
selectedChainId,
|
|
20
20
|
}: Props) => {
|
|
21
|
-
const { supportedChains } = useSwapContext();
|
|
21
|
+
const { supportedChains, tokenPrices } = useSwapContext();
|
|
22
22
|
const { address } = useAccount();
|
|
23
23
|
|
|
24
24
|
const chain = useMemo(
|
|
@@ -26,6 +26,26 @@ export const TokenItem = ({
|
|
|
26
26
|
[supportedChains, token],
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
+
const tokenPrice = useMemo(() => {
|
|
30
|
+
const prices = tokenPrices[token.chainId];
|
|
31
|
+
return prices?.[token.address];
|
|
32
|
+
}, [token, tokenPrices]);
|
|
33
|
+
|
|
34
|
+
const tokenBalance = useMemo(() => {
|
|
35
|
+
if (!token.balance || !token.decimals) return null;
|
|
36
|
+
return Number(ethers.utils.formatUnits(token.balance, token.decimals));
|
|
37
|
+
}, [token.balance, token.decimals]);
|
|
38
|
+
|
|
39
|
+
const hasBalance = useMemo(
|
|
40
|
+
() => token.balance && !token.balance.eq(0),
|
|
41
|
+
[token.balance],
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const tokenValueUsd = useMemo(() => {
|
|
45
|
+
if (!tokenBalance || !tokenPrice || !hasBalance) return null;
|
|
46
|
+
return tokenBalance * +tokenPrice;
|
|
47
|
+
}, [tokenBalance, tokenPrice, hasBalance]);
|
|
48
|
+
|
|
29
49
|
return (
|
|
30
50
|
<div
|
|
31
51
|
className={`token-picker-container ${
|
|
@@ -55,16 +75,21 @@ export const TokenItem = ({
|
|
|
55
75
|
</div>
|
|
56
76
|
|
|
57
77
|
{token.balance && token.decimals ? (
|
|
58
|
-
<div className="text-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
78
|
+
<div className="text-right">
|
|
79
|
+
<div className="text-xs text-t_text_primary">
|
|
80
|
+
{token.balance.eq(0) || tokenBalance! > 0.0001
|
|
81
|
+
? weiToHumanReadable({
|
|
82
|
+
amount: token.balance.toString(),
|
|
83
|
+
decimals: token.decimals,
|
|
84
|
+
precisionFractionalPlaces: 4,
|
|
85
|
+
})
|
|
86
|
+
: "<0.0001"}
|
|
87
|
+
</div>
|
|
88
|
+
{hasBalance && (
|
|
89
|
+
<div className="text-xs text-t_text_primary text-opacity-50">
|
|
90
|
+
{tokenValueUsd ? `$${tokenValueUsd.toFixed(2)}` : "$ -"}
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
68
93
|
</div>
|
|
69
94
|
) : (
|
|
70
95
|
<>
|
|
@@ -51,8 +51,12 @@ export const TokenPicker = ({
|
|
|
51
51
|
const currentRouteRequestNonce = useRef<number>(0);
|
|
52
52
|
const tokenSearchRef = useRef<HTMLInputElement | null>(null);
|
|
53
53
|
|
|
54
|
-
const {
|
|
55
|
-
|
|
54
|
+
const {
|
|
55
|
+
bridgeUI,
|
|
56
|
+
supportedChains,
|
|
57
|
+
findTokenDataByAddressAndChain,
|
|
58
|
+
tokenPrices,
|
|
59
|
+
} = useSwapContext();
|
|
56
60
|
const { address } = useAccount();
|
|
57
61
|
const evmContractApi = useEvmContractApi();
|
|
58
62
|
|
|
@@ -191,6 +195,15 @@ export const TokenPicker = ({
|
|
|
191
195
|
}, [isOpen]);
|
|
192
196
|
|
|
193
197
|
const allTokens = useMemo(() => {
|
|
198
|
+
const calculateTokenValue = (token: TokenOption) => {
|
|
199
|
+
if (!token.balance || !token.decimals) return 0;
|
|
200
|
+
const balance = Number(
|
|
201
|
+
ethers.utils.formatUnits(token.balance, token.decimals),
|
|
202
|
+
);
|
|
203
|
+
const price = tokenPrices[token.chainId]?.[token.address];
|
|
204
|
+
return price ? balance * Number(price) : 0;
|
|
205
|
+
};
|
|
206
|
+
|
|
194
207
|
const ownedFilteredTokens = [
|
|
195
208
|
...filteredTokens.filter((token) =>
|
|
196
209
|
BigNumber.from(token?.balance || "0").gt(0),
|
|
@@ -198,9 +211,16 @@ export const TokenPicker = ({
|
|
|
198
211
|
...otherFilteredTokens.filter((token) =>
|
|
199
212
|
BigNumber.from(token?.balance || "0").gt(0),
|
|
200
213
|
),
|
|
201
|
-
].sort(
|
|
202
|
-
|
|
203
|
-
|
|
214
|
+
].sort((tokenA, tokenB) => {
|
|
215
|
+
const valueA = calculateTokenValue(tokenA);
|
|
216
|
+
const valueB = calculateTokenValue(tokenB);
|
|
217
|
+
// First sort by USD value
|
|
218
|
+
if (valueB !== valueA) {
|
|
219
|
+
return valueB - valueA;
|
|
220
|
+
}
|
|
221
|
+
// If USD values are equal (or both 0), sort by priority
|
|
222
|
+
return tokenB.priority - tokenA.priority;
|
|
223
|
+
});
|
|
204
224
|
|
|
205
225
|
const currentChainTokens = filteredTokens
|
|
206
226
|
.filter((token) => BigNumber.from(token?.balance || "0").eq(0))
|
|
@@ -231,7 +251,7 @@ export const TokenPicker = ({
|
|
|
231
251
|
];
|
|
232
252
|
|
|
233
253
|
return groups.flat();
|
|
234
|
-
}, [filteredTokens, otherFilteredTokens, chain, address]);
|
|
254
|
+
}, [filteredTokens, otherFilteredTokens, chain, address, tokenPrices]);
|
|
235
255
|
|
|
236
256
|
const ownedTokens = useMemo(
|
|
237
257
|
() => allTokens.filter((token) => token.balance?.gt(0)),
|
|
@@ -113,7 +113,11 @@ export const TokenPanel = ({ chain, token, type, className }: Props) => {
|
|
|
113
113
|
<div className="flex flex-col font-medium items-start">
|
|
114
114
|
<p className="text-xs opacity-60">Token: </p>
|
|
115
115
|
<p className={`${token ? "" : "opacity-60"}`}>
|
|
116
|
-
{token
|
|
116
|
+
{token
|
|
117
|
+
? token.symbol
|
|
118
|
+
: type === "destination" && bridgeUI
|
|
119
|
+
? "-"
|
|
120
|
+
: "Select"}
|
|
117
121
|
</p>
|
|
118
122
|
</div>
|
|
119
123
|
</div>
|
|
@@ -38,7 +38,7 @@ export const SwapPanel = ({ type }: Props) => {
|
|
|
38
38
|
/>
|
|
39
39
|
</div>
|
|
40
40
|
<div
|
|
41
|
-
className={`flex justify-between ${
|
|
41
|
+
className={`flex justify-between rounded-b-[11px] ${
|
|
42
42
|
type === "destination" &&
|
|
43
43
|
"bg-gradient-to-r from-t_main_accent_light/20 to-t_main_accent_dark/20"
|
|
44
44
|
}`}
|
|
@@ -7,8 +7,8 @@ export type SwapPanelType = "source" | "destination";
|
|
|
7
7
|
|
|
8
8
|
export const SwapView = () => {
|
|
9
9
|
return (
|
|
10
|
-
<div className="flex flex-col gap-
|
|
11
|
-
<div className="flex flex-col gap-[
|
|
10
|
+
<div className="flex flex-col gap-6 fill-t_text_primary">
|
|
11
|
+
<div className="flex flex-col gap-[11px]">
|
|
12
12
|
<SwapPanel type="source" />
|
|
13
13
|
<ReorderButton />
|
|
14
14
|
<SwapPanel type="destination" />
|
|
@@ -13,7 +13,7 @@ const positionToClass: Record<Position, string> = {
|
|
|
13
13
|
|
|
14
14
|
export const Tooltip: FC<{
|
|
15
15
|
id: string;
|
|
16
|
-
position:
|
|
16
|
+
position: Position;
|
|
17
17
|
text: string;
|
|
18
18
|
triggerRef: RefObject<Element>;
|
|
19
19
|
}> = ({ id, position, text, triggerRef }) => {
|
|
@@ -64,8 +64,7 @@ type SwapContext = {
|
|
|
64
64
|
setSrcChain: Dispatch<SetStateAction<Chain | undefined>>;
|
|
65
65
|
srcChainTokensOptions: TokenOption[];
|
|
66
66
|
srcChainOtherTokensOptions: TokenOption[];
|
|
67
|
-
|
|
68
|
-
dstChainTokensPrices: TokenPrices;
|
|
67
|
+
tokenPrices: TokenPrices;
|
|
69
68
|
srcToken: Token | undefined;
|
|
70
69
|
setSrcToken: Dispatch<SetStateAction<Token | undefined>>;
|
|
71
70
|
dstChain: Chain | undefined;
|
|
@@ -128,8 +127,7 @@ const init: SwapContext = {
|
|
|
128
127
|
srcChain: undefined,
|
|
129
128
|
srcChainTokensOptions: [],
|
|
130
129
|
srcChainOtherTokensOptions: [],
|
|
131
|
-
|
|
132
|
-
dstChainTokensPrices: {},
|
|
130
|
+
tokenPrices: {},
|
|
133
131
|
dstChain: undefined,
|
|
134
132
|
dstChainTokensOptions: [],
|
|
135
133
|
dstChainOtherTokensOptions: [],
|
|
@@ -246,12 +244,7 @@ export const SwapProvider = ({
|
|
|
246
244
|
const [dstChainTokensOptions, setDstChainTokensOptions] = useState(
|
|
247
245
|
init.dstChainTokensOptions,
|
|
248
246
|
);
|
|
249
|
-
const [
|
|
250
|
-
init.srcChainTokensPrices,
|
|
251
|
-
);
|
|
252
|
-
const [dstChainTokensPrices, setDstChainTokensPrices] = useState(
|
|
253
|
-
init.dstChainTokensPrices,
|
|
254
|
-
);
|
|
247
|
+
const [tokenPrices, setTokenPrices] = useState(init.tokenPrices);
|
|
255
248
|
const [srcChainOtherTokensOptions, setSrcChainOtherTokensOptions] = useState(
|
|
256
249
|
init.srcChainOtherTokensOptions,
|
|
257
250
|
);
|
|
@@ -265,6 +258,15 @@ export const SwapProvider = ({
|
|
|
265
258
|
|
|
266
259
|
const { history } = useHistory();
|
|
267
260
|
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
if (supportedChains.length > 0) {
|
|
263
|
+
const chainIds = supportedChains.map((chain) => chain.chainId);
|
|
264
|
+
getPrices({ chainId: chainIds }).then((prices) => {
|
|
265
|
+
setTokenPrices(prices);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}, [supportedChains]);
|
|
269
|
+
|
|
268
270
|
const supportedTokens: Record<string, Record<string, Token>> = useMemo(() => {
|
|
269
271
|
const customTokens = !isServer
|
|
270
272
|
? JSON.parse(localStorage.getItem("custom-tokens") || "{}")
|
|
@@ -406,36 +408,21 @@ export const SwapProvider = ({
|
|
|
406
408
|
[srcToken?.decimals, srcValue],
|
|
407
409
|
);
|
|
408
410
|
|
|
409
|
-
// fetch srcTokenPrices
|
|
410
|
-
useEffect(() => {
|
|
411
|
-
if (srcChain) {
|
|
412
|
-
getPrices({ chainId: srcChain.chainId, currency: "USD" }).then((prices) =>
|
|
413
|
-
setSrcChainTokensPrices(prices),
|
|
414
|
-
);
|
|
415
|
-
}
|
|
416
|
-
}, [srcChain]);
|
|
417
|
-
|
|
418
|
-
// fetch dstTokenPrices
|
|
419
|
-
useEffect(() => {
|
|
420
|
-
if (dstChain) {
|
|
421
|
-
getPrices({ chainId: dstChain.chainId, currency: "USD" }).then((prices) =>
|
|
422
|
-
setDstChainTokensPrices(prices),
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
}, [dstChain]);
|
|
426
|
-
|
|
427
411
|
const srcValueUsd = useMemo(() => {
|
|
428
412
|
if (
|
|
429
413
|
srcToken &&
|
|
430
|
-
|
|
431
|
-
|
|
414
|
+
srcChain &&
|
|
415
|
+
tokenPrices &&
|
|
416
|
+
tokenPrices[srcChain.chainId] &&
|
|
417
|
+
tokenPrices[srcChain.chainId]?.[srcToken.address]
|
|
432
418
|
) {
|
|
433
419
|
return (
|
|
434
|
-
Number(srcValue) *
|
|
420
|
+
Number(srcValue) *
|
|
421
|
+
Number(tokenPrices[srcChain.chainId]?.[srcToken.address])
|
|
435
422
|
).toFixed(2);
|
|
436
423
|
}
|
|
437
424
|
return null;
|
|
438
|
-
}, [
|
|
425
|
+
}, [tokenPrices, srcToken, srcValue, srcChain]);
|
|
439
426
|
const dstValue = useMemo(
|
|
440
427
|
() =>
|
|
441
428
|
weiToHumanReadable({
|
|
@@ -457,15 +444,18 @@ export const SwapProvider = ({
|
|
|
457
444
|
const dstValueUsd = useMemo(() => {
|
|
458
445
|
if (
|
|
459
446
|
dstToken &&
|
|
460
|
-
|
|
461
|
-
|
|
447
|
+
dstChain &&
|
|
448
|
+
tokenPrices &&
|
|
449
|
+
tokenPrices[dstChain?.chainId] &&
|
|
450
|
+
tokenPrices[dstChain?.chainId]?.[dstToken.address]
|
|
462
451
|
) {
|
|
463
452
|
return (
|
|
464
|
-
Number(dstValue) *
|
|
453
|
+
Number(dstValue) *
|
|
454
|
+
Number(tokenPrices[dstChain?.chainId]?.[dstToken.address])
|
|
465
455
|
).toFixed(2);
|
|
466
456
|
}
|
|
467
457
|
return null;
|
|
468
|
-
}, [
|
|
458
|
+
}, [tokenPrices, dstToken, dstValue, dstChain]);
|
|
469
459
|
const dstValueMin = useMemo(
|
|
470
460
|
() =>
|
|
471
461
|
weiToHumanReadable({
|
|
@@ -950,8 +940,7 @@ export const SwapProvider = ({
|
|
|
950
940
|
setSrcChain,
|
|
951
941
|
srcChainTokensOptions,
|
|
952
942
|
srcChainOtherTokensOptions,
|
|
953
|
-
|
|
954
|
-
srcChainTokensPrices,
|
|
943
|
+
tokenPrices,
|
|
955
944
|
dstChain,
|
|
956
945
|
setDstChain,
|
|
957
946
|
dstChainTokensOptions,
|
package/src/models/TokenData.ts
CHANGED