@xswap-link/sdk 0.8.6 → 0.8.7
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/pr_agent.yml +22 -0
- package/CHANGELOG.md +6 -0
- package/dist/index.global.js +116 -116
- package/dist/index.js +10 -10
- package/dist/index.mjs +9 -9
- package/package.json +1 -1
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +5 -7
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +18 -2
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +1 -24
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx +2 -11
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +1 -1
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +13 -6
- package/src/constants/index.ts +1 -1
- package/src/context/SwapProvider.tsx +66 -41
- package/src/utils/validation.ts +199 -180
package/package.json
CHANGED
|
@@ -9,11 +9,11 @@ import { useMemo, useRef } from "react";
|
|
|
9
9
|
type Props = {
|
|
10
10
|
chain: Chain;
|
|
11
11
|
type: SwapPanelType;
|
|
12
|
-
|
|
12
|
+
disabled: boolean;
|
|
13
13
|
onClick: (chainId: string) => void;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export const ChainItem = ({ chain, type, onClick,
|
|
16
|
+
export const ChainItem = ({ chain, type, onClick, disabled }: Props) => {
|
|
17
17
|
const {
|
|
18
18
|
networks: { evm },
|
|
19
19
|
} = useNetworks();
|
|
@@ -40,12 +40,10 @@ export const ChainItem = ({ chain, type, onClick, disabledChains }: Props) => {
|
|
|
40
40
|
return type === "destination" ? srcChain?.chainId : dstChain?.chainId;
|
|
41
41
|
}, [bridgeUI, dstChain?.chainId, srcChain?.chainId, type]);
|
|
42
42
|
|
|
43
|
-
const isInDisabledChains = disabledChains.includes(chain.chainId);
|
|
44
|
-
|
|
45
43
|
return (
|
|
46
44
|
<div
|
|
47
45
|
onClick={() => {
|
|
48
|
-
if (chain.chainId === sameChainId ||
|
|
46
|
+
if (chain.chainId === sameChainId || disabled) {
|
|
49
47
|
return;
|
|
50
48
|
}
|
|
51
49
|
onClick(chain.chainId);
|
|
@@ -53,7 +51,7 @@ export const ChainItem = ({ chain, type, onClick, disabledChains }: Props) => {
|
|
|
53
51
|
className={`flex justify-between items-center gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-chain-item ${
|
|
54
52
|
currentChainId === chain.chainId ? "selected-chain-item" : ""
|
|
55
53
|
} ${
|
|
56
|
-
chain.chainId === sameChainId ||
|
|
54
|
+
chain.chainId === sameChainId || disabled
|
|
57
55
|
? "disabled-chain-item cursor-default"
|
|
58
56
|
: ""
|
|
59
57
|
}`}
|
|
@@ -70,7 +68,7 @@ export const ChainItem = ({ chain, type, onClick, disabledChains }: Props) => {
|
|
|
70
68
|
</div>
|
|
71
69
|
)}
|
|
72
70
|
|
|
73
|
-
{
|
|
71
|
+
{disabled && chain.chainId !== sameChainId && (
|
|
74
72
|
<div className="flex items-center gap-1">
|
|
75
73
|
<Tooltip
|
|
76
74
|
text={
|
|
@@ -101,6 +101,22 @@ export const ChainPicker = ({
|
|
|
101
101
|
supportedChains,
|
|
102
102
|
]);
|
|
103
103
|
|
|
104
|
+
const sortedChains = useMemo(() => {
|
|
105
|
+
return filteredChains
|
|
106
|
+
.map((chain) => ({
|
|
107
|
+
...chain,
|
|
108
|
+
disabled: disabledChains.includes(chain.chainId),
|
|
109
|
+
}))
|
|
110
|
+
.sort((a, b) => {
|
|
111
|
+
if (a.disabled === b.disabled) {
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Place false before true.
|
|
116
|
+
return a.disabled ? 1 : -1;
|
|
117
|
+
});
|
|
118
|
+
}, [filteredChains, disabledChains]);
|
|
119
|
+
|
|
104
120
|
return (
|
|
105
121
|
<div className="flex flex-col h-full">
|
|
106
122
|
<div className="flex justify-between">
|
|
@@ -117,12 +133,12 @@ export const ChainPicker = ({
|
|
|
117
133
|
{filteredChains.length ? (
|
|
118
134
|
<Virtuoso
|
|
119
135
|
style={{ height: "100%" }}
|
|
120
|
-
data={
|
|
136
|
+
data={sortedChains}
|
|
121
137
|
itemContent={(_, chain) => (
|
|
122
138
|
<ChainItem
|
|
123
139
|
chain={chain}
|
|
124
140
|
type={type}
|
|
125
|
-
|
|
141
|
+
disabled={chain.disabled}
|
|
126
142
|
onClick={select}
|
|
127
143
|
/>
|
|
128
144
|
)}
|
|
@@ -2,8 +2,7 @@ import { ArrowDownIcon } from "@src/assets/icons";
|
|
|
2
2
|
import { Modal } from "@src/components/Modal";
|
|
3
3
|
import { useSwapContext } from "@src/context";
|
|
4
4
|
import { Chain, Token } from "@src/models";
|
|
5
|
-
import { useCallback,
|
|
6
|
-
import { useAccount } from "wagmi";
|
|
5
|
+
import { useCallback, useMemo, useState } from "react";
|
|
7
6
|
import { SwapPanelType } from "../../../SwapView";
|
|
8
7
|
import { ChainPicker } from "./ChainPicker";
|
|
9
8
|
|
|
@@ -15,8 +14,6 @@ type Props = {
|
|
|
15
14
|
|
|
16
15
|
export const ChainPanel = ({ chain, type, className }: Props) => {
|
|
17
16
|
const {
|
|
18
|
-
supportedChains,
|
|
19
|
-
srcChain,
|
|
20
17
|
setSrcChain,
|
|
21
18
|
setDstChain,
|
|
22
19
|
srcToken,
|
|
@@ -25,13 +22,10 @@ export const ChainPanel = ({ chain, type, className }: Props) => {
|
|
|
25
22
|
setDstToken,
|
|
26
23
|
srcChainLocked,
|
|
27
24
|
dstChainLocked,
|
|
28
|
-
integrationConfig,
|
|
29
25
|
bridgeUI,
|
|
30
26
|
bridgeTokensDictionary,
|
|
31
27
|
} = useSwapContext();
|
|
32
28
|
|
|
33
|
-
const { chainId } = useAccount();
|
|
34
|
-
|
|
35
29
|
const projectLockedDestinationChain = useMemo(
|
|
36
30
|
() => type === "destination" && dstChainLocked,
|
|
37
31
|
[type, dstChainLocked],
|
|
@@ -42,23 +36,6 @@ export const ChainPanel = ({ chain, type, className }: Props) => {
|
|
|
42
36
|
[type, srcChainLocked],
|
|
43
37
|
);
|
|
44
38
|
|
|
45
|
-
// select chain from user wallet
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
if (!chainId || integrationConfig.srcChainId) return;
|
|
48
|
-
|
|
49
|
-
const userChainFromWallet = supportedChains.find(
|
|
50
|
-
(chain) => chain.chainId === String(chainId),
|
|
51
|
-
);
|
|
52
|
-
if (
|
|
53
|
-
!userChainFromWallet ||
|
|
54
|
-
srcChain?.chainId === userChainFromWallet.chainId
|
|
55
|
-
)
|
|
56
|
-
return;
|
|
57
|
-
|
|
58
|
-
setSrcChain(userChainFromWallet);
|
|
59
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
60
|
-
}, [chainId]);
|
|
61
|
-
|
|
62
39
|
const [chainPickerModalOpen, setChainPickerModalOpen] = useState(false);
|
|
63
40
|
|
|
64
41
|
const handleSrcChainChange = useCallback(
|
package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { TokenLogo } from "@src/components";
|
|
2
|
-
import { useSwapContext } from "@src/context";
|
|
3
2
|
import { TokenOption } from "@src/models";
|
|
4
|
-
import { useMemo } from "react";
|
|
5
3
|
|
|
6
4
|
type Props = {
|
|
7
5
|
token: TokenOption;
|
|
@@ -13,13 +11,6 @@ export const QuickPickTokenItem = ({
|
|
|
13
11
|
selectedTokenAddress,
|
|
14
12
|
onClick,
|
|
15
13
|
}: Props) => {
|
|
16
|
-
const { supportedChains } = useSwapContext();
|
|
17
|
-
|
|
18
|
-
const chain = useMemo(
|
|
19
|
-
() => supportedChains.find(({ chainId }) => chainId === token.chainId),
|
|
20
|
-
[supportedChains, token],
|
|
21
|
-
);
|
|
22
|
-
|
|
23
14
|
return (
|
|
24
15
|
<button
|
|
25
16
|
type="button"
|
|
@@ -36,9 +27,9 @@ export const QuickPickTokenItem = ({
|
|
|
36
27
|
generatedLogoClassName="w-6 h-6"
|
|
37
28
|
/>
|
|
38
29
|
<div className="flex flex-col gap-1 text-xs font-medium !leading-3">
|
|
39
|
-
<div className="text-t_text_primary">{token.
|
|
30
|
+
<div className="text-t_text_primary">{token.name}</div>
|
|
40
31
|
<div className="text-t_text_primary text-opacity-50">
|
|
41
|
-
{
|
|
32
|
+
{token.symbol}
|
|
42
33
|
</div>
|
|
43
34
|
</div>
|
|
44
35
|
</button>
|
|
@@ -22,7 +22,7 @@ import { TokenItem } from "./TokenItem";
|
|
|
22
22
|
|
|
23
23
|
type Props = {
|
|
24
24
|
type: SwapPanelType;
|
|
25
|
-
chain
|
|
25
|
+
chain?: Chain;
|
|
26
26
|
tokens: TokenOption[];
|
|
27
27
|
otherTokens: TokenOption[];
|
|
28
28
|
selectedTokenAddress?: string;
|
|
@@ -59,7 +59,7 @@ export const TokenPicker = ({
|
|
|
59
59
|
}, [isOpen]);
|
|
60
60
|
|
|
61
61
|
const importCustomToken = useCallback(() => {
|
|
62
|
-
if (customTokenData && isETHAddressValid(searchValue)) {
|
|
62
|
+
if (chain && customTokenData && isETHAddressValid(searchValue)) {
|
|
63
63
|
let customTokens = {};
|
|
64
64
|
if (!isServer) {
|
|
65
65
|
customTokens = JSON.parse(
|
|
@@ -97,7 +97,7 @@ export const TokenPicker = ({
|
|
|
97
97
|
currentRouteRequestNonce.current = nonce;
|
|
98
98
|
const rpcUrl = supportedChains.find(
|
|
99
99
|
({ ecosystem, chainId }) =>
|
|
100
|
-
ecosystem === Ecosystem.EVM && chainId === chain
|
|
100
|
+
ecosystem === Ecosystem.EVM && chainId === chain?.chainId,
|
|
101
101
|
)?.publicRpcUrls[0];
|
|
102
102
|
const customTokenContract = new ethers.Contract(
|
|
103
103
|
searchValue.toLowerCase(),
|
|
@@ -134,6 +134,7 @@ export const TokenPicker = ({
|
|
|
134
134
|
if (
|
|
135
135
|
!bridgeUI &&
|
|
136
136
|
isETHAddressValid(searchValue) &&
|
|
137
|
+
chain &&
|
|
137
138
|
!findTokenDataByAddressAndChain(searchValue.toLowerCase(), chain.chainId)
|
|
138
139
|
) {
|
|
139
140
|
getCustomTokenData();
|
|
@@ -385,9 +386,15 @@ export const TokenPicker = ({
|
|
|
385
386
|
groupContent={(index) => (
|
|
386
387
|
<div className="py-1 bg-t_bg_primary text-t_text_primary">
|
|
387
388
|
<div className="px-4 text-left">
|
|
388
|
-
{
|
|
389
|
-
|
|
390
|
-
|
|
389
|
+
{(() => {
|
|
390
|
+
if (chain) {
|
|
391
|
+
return index === 0
|
|
392
|
+
? `${chain.displayName} network`
|
|
393
|
+
: "Other networks";
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return "All networks";
|
|
397
|
+
})()}
|
|
391
398
|
</div>
|
|
392
399
|
<div className="horizontal-separator" />
|
|
393
400
|
{!tokenGroups[index]?.length && (
|
package/src/constants/index.ts
CHANGED
|
@@ -12,7 +12,7 @@ export const ROUTE_TIMEOUT_MS = 10000;
|
|
|
12
12
|
export const MINIMUM_DISPLAYED_TOKEN_AMOUNT = 0.0001;
|
|
13
13
|
export const DEFAULT_SOURCE_CHAIN_ID = "1";
|
|
14
14
|
export const DEFAULT_SOURCE_TOKEN_ADDR = constants.AddressZero;
|
|
15
|
-
export const DEFAULT_DESTINATION_CHAIN_ID = "
|
|
15
|
+
export const DEFAULT_DESTINATION_CHAIN_ID = "1";
|
|
16
16
|
export const DEFAULT_DESTINATION_TOKEN_ADDR =
|
|
17
17
|
"0x8fe815417913a93ea99049fc0718ee1647a2a07c"; // XSWAP token
|
|
18
18
|
export const CCIP_EXPLORER = "https://ccip.chain.link/";
|
|
@@ -194,7 +194,7 @@ export const SwapProvider = ({
|
|
|
194
194
|
wagmiConfig,
|
|
195
195
|
overlay,
|
|
196
196
|
}: Props) => {
|
|
197
|
-
const { address } = useAccount();
|
|
197
|
+
const { address, chainId: walletChainId } = useAccount();
|
|
198
198
|
const [tab, setTab] = useState(init.tab);
|
|
199
199
|
const [error, setError] = useState(init.error);
|
|
200
200
|
const [expressDelivery, setExpressDelivery] = useState(init.expressDelivery);
|
|
@@ -560,16 +560,13 @@ export const SwapProvider = ({
|
|
|
560
560
|
}, [quoteRoute]);
|
|
561
561
|
|
|
562
562
|
useEffect(() => {
|
|
563
|
-
if (!srcChain || !dstChain) {
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
563
|
(async () => {
|
|
567
564
|
// source chain
|
|
568
565
|
const srcTokenOptions: TokenOption[] = getTokenOptions(
|
|
569
|
-
srcChain
|
|
570
|
-
dstChain
|
|
566
|
+
srcChain?.chainId,
|
|
567
|
+
dstChain?.chainId,
|
|
571
568
|
).filter(({ symbol }) =>
|
|
572
|
-
dstChain
|
|
569
|
+
dstChain?.chainId === srcChain?.chainId
|
|
573
570
|
? symbol !== dstToken?.symbol
|
|
574
571
|
: true,
|
|
575
572
|
);
|
|
@@ -577,10 +574,10 @@ export const SwapProvider = ({
|
|
|
577
574
|
|
|
578
575
|
// destination chain
|
|
579
576
|
const dstTokenOptions: TokenOption[] = getTokenOptions(
|
|
580
|
-
dstChain
|
|
581
|
-
|
|
577
|
+
dstChain?.chainId,
|
|
578
|
+
dstChain?.chainId,
|
|
582
579
|
).filter(({ symbol }) =>
|
|
583
|
-
dstChain
|
|
580
|
+
dstChain?.chainId === srcChain?.chainId
|
|
584
581
|
? symbol !== srcToken?.symbol
|
|
585
582
|
: true,
|
|
586
583
|
);
|
|
@@ -591,7 +588,7 @@ export const SwapProvider = ({
|
|
|
591
588
|
const srcOtherChains = supportedChains.filter(
|
|
592
589
|
({ chainId, web3Environment, swapSupported, bridgeSupported }) => {
|
|
593
590
|
if (
|
|
594
|
-
chainId === srcChain
|
|
591
|
+
chainId === srcChain?.chainId ||
|
|
595
592
|
web3Environment !== Web3Environment.MAINNET
|
|
596
593
|
) {
|
|
597
594
|
return false;
|
|
@@ -606,8 +603,8 @@ export const SwapProvider = ({
|
|
|
606
603
|
);
|
|
607
604
|
for (const { chainId } of srcOtherChains) {
|
|
608
605
|
srcOtherTokenOptions.push(
|
|
609
|
-
...getTokenOptions(chainId, dstChain
|
|
610
|
-
chainId === dstChain
|
|
606
|
+
...getTokenOptions(chainId, dstChain?.chainId).filter(({ symbol }) =>
|
|
607
|
+
chainId === dstChain?.chainId ? symbol !== dstToken?.symbol : true,
|
|
611
608
|
),
|
|
612
609
|
);
|
|
613
610
|
}
|
|
@@ -617,14 +614,14 @@ export const SwapProvider = ({
|
|
|
617
614
|
const dstOtherTokenOptions: TokenOption[] = [];
|
|
618
615
|
const dstOtherChains = supportedChains.filter(
|
|
619
616
|
({ chainId, web3Environment, swapSupported }) =>
|
|
620
|
-
chainId !== dstChain
|
|
617
|
+
chainId !== dstChain?.chainId &&
|
|
621
618
|
web3Environment === Web3Environment.MAINNET &&
|
|
622
619
|
swapSupported,
|
|
623
620
|
);
|
|
624
621
|
for (const { chainId } of dstOtherChains) {
|
|
625
622
|
dstOtherTokenOptions.push(
|
|
626
|
-
...getTokenOptions(chainId,
|
|
627
|
-
chainId === srcChain
|
|
623
|
+
...getTokenOptions(chainId, dstChain?.chainId).filter(({ symbol }) =>
|
|
624
|
+
chainId === srcChain?.chainId ? symbol !== srcToken?.symbol : true,
|
|
628
625
|
),
|
|
629
626
|
);
|
|
630
627
|
}
|
|
@@ -657,6 +654,7 @@ export const SwapProvider = ({
|
|
|
657
654
|
}
|
|
658
655
|
})();
|
|
659
656
|
}, [
|
|
657
|
+
bridgeUI,
|
|
660
658
|
srcChain,
|
|
661
659
|
dstChain,
|
|
662
660
|
address,
|
|
@@ -717,33 +715,60 @@ export const SwapProvider = ({
|
|
|
717
715
|
}, [srcChain]);
|
|
718
716
|
|
|
719
717
|
useEffect(() => {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
(
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
chainId ===
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
718
|
+
setSrcChain((state) => {
|
|
719
|
+
const searchedChainId =
|
|
720
|
+
// currently set chain
|
|
721
|
+
state?.chainId ||
|
|
722
|
+
// chain set by the integrator
|
|
723
|
+
integrationConfig?.srcChainId ||
|
|
724
|
+
// wallet chain
|
|
725
|
+
(walletChainId ? `${walletChainId}` : undefined) ||
|
|
726
|
+
// default chain
|
|
727
|
+
(bridgeUI ? undefined : DEFAULT_SOURCE_CHAIN_ID);
|
|
728
|
+
|
|
729
|
+
const initSrcChain = supportedChains.find(
|
|
730
|
+
({ chainId }) => chainId === searchedChainId,
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
if (initSrcChain) {
|
|
734
|
+
const initSrcToken = initSrcChain.tokens.find(
|
|
735
|
+
({ address }) =>
|
|
736
|
+
address.toLowerCase() ===
|
|
737
|
+
(integrationConfig?.srcTokenAddr?.toLowerCase() ||
|
|
738
|
+
DEFAULT_SOURCE_TOKEN_ADDR.toLowerCase()),
|
|
739
|
+
);
|
|
741
740
|
|
|
742
|
-
|
|
743
|
-
|
|
741
|
+
// This useEffect is only triggered by config and wallet changes.
|
|
742
|
+
// So it will run when user connects wallet.
|
|
743
|
+
// We want to keep the token that was already selected before connecting and only use initSrcToken if the token filed was empty.
|
|
744
|
+
setSrcToken((state) => state || initSrcToken);
|
|
745
|
+
} else {
|
|
746
|
+
setSrcToken(undefined);
|
|
747
|
+
}
|
|
748
|
+
return initSrcChain;
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
const initDstChain = bridgeUI
|
|
752
|
+
? undefined
|
|
753
|
+
: supportedChains.find(
|
|
754
|
+
({ chainId }) =>
|
|
755
|
+
chainId ===
|
|
756
|
+
(integrationConfig.dstChainId || DEFAULT_DESTINATION_CHAIN_ID),
|
|
757
|
+
);
|
|
744
758
|
setDstChain(initDstChain);
|
|
745
|
-
|
|
746
|
-
|
|
759
|
+
|
|
760
|
+
if (initDstChain) {
|
|
761
|
+
const initDstToken = initDstChain.tokens.find(
|
|
762
|
+
({ address }) =>
|
|
763
|
+
address.toLowerCase() ===
|
|
764
|
+
(integrationConfig.dstTokenAddr?.toLowerCase() ||
|
|
765
|
+
DEFAULT_DESTINATION_TOKEN_ADDR.toLowerCase()),
|
|
766
|
+
);
|
|
767
|
+
setDstToken(initDstToken);
|
|
768
|
+
} else {
|
|
769
|
+
setDstToken(undefined);
|
|
770
|
+
}
|
|
771
|
+
}, [integrationConfig, supportedChains, bridgeUI, walletChainId]);
|
|
747
772
|
|
|
748
773
|
useEffect(() => {
|
|
749
774
|
if (!bridgeTokensDictionary) {
|