@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
|
@@ -117,7 +117,7 @@ type SwapContext = {
|
|
|
117
117
|
isFetchingBalances: boolean;
|
|
118
118
|
isExpressDeliveryActive: boolean;
|
|
119
119
|
quoteRoute: () => Promise<void>;
|
|
120
|
-
refreshBalance: () => void;
|
|
120
|
+
refreshBalance: (options?: { forceRpc?: boolean }) => void;
|
|
121
121
|
findTokenDataByAddressAndChain: (
|
|
122
122
|
tokenAddress: string,
|
|
123
123
|
chainId: string,
|
|
@@ -279,6 +279,7 @@ export const SwapProvider = ({
|
|
|
279
279
|
|
|
280
280
|
const routeAbortController = useRef<AbortController | null>(null);
|
|
281
281
|
const refreshSelectedTokenBalanceNonce = useRef(crypto.randomUUID());
|
|
282
|
+
const prevWalletAddresses = useRef<string | undefined>(undefined);
|
|
282
283
|
|
|
283
284
|
// =============================================================================
|
|
284
285
|
// Memoized Values
|
|
@@ -668,77 +669,96 @@ export const SwapProvider = ({
|
|
|
668
669
|
srcValueWei,
|
|
669
670
|
]);
|
|
670
671
|
// refreshes and updates the balance of the source token using its RPC URL.
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
refreshSelectedTokenBalanceNonce.current = nonce;
|
|
683
|
-
setIsFetchingBalance(true);
|
|
684
|
-
let balance = "0";
|
|
685
|
-
if (srcChain?.ecosystem === Ecosystem.EVM && evmAddress) {
|
|
686
|
-
const balanceFromBackend =
|
|
687
|
-
tokenBalances[srcChain?.chainId]?.[srcToken.address];
|
|
688
|
-
if (balanceFromBackend === undefined) {
|
|
689
|
-
const balanceUI = await getBalanceOf(
|
|
690
|
-
evmAddress,
|
|
691
|
-
srcToken.address,
|
|
692
|
-
srcChain?.publicRpcUrls[0],
|
|
693
|
-
);
|
|
694
|
-
balance = humanReadableToWei({
|
|
695
|
-
amount: balanceUI,
|
|
696
|
-
decimals: srcToken.decimals,
|
|
697
|
-
});
|
|
698
|
-
} else {
|
|
699
|
-
balance = balanceFromBackend;
|
|
672
|
+
// pass { forceRpc: true } to skip the backend balances cache (e.g. right
|
|
673
|
+
// after a transaction, when the cached value is already stale).
|
|
674
|
+
const refreshBalance = useCallback(
|
|
675
|
+
async (options?: { forceRpc?: boolean }) => {
|
|
676
|
+
if (
|
|
677
|
+
(!evmAddress && !solanaAddress) ||
|
|
678
|
+
!srcChain?.publicRpcUrls[0] ||
|
|
679
|
+
!srcToken ||
|
|
680
|
+
!srcToken?.address
|
|
681
|
+
) {
|
|
682
|
+
return;
|
|
700
683
|
}
|
|
701
|
-
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
684
|
+
|
|
685
|
+
const nonce = crypto.randomUUID();
|
|
686
|
+
refreshSelectedTokenBalanceNonce.current = nonce;
|
|
687
|
+
setIsFetchingBalance(true);
|
|
688
|
+
let balance = "0";
|
|
689
|
+
if (srcChain?.ecosystem === Ecosystem.EVM && evmAddress) {
|
|
690
|
+
const balanceFromBackend =
|
|
691
|
+
tokenBalances[srcChain?.chainId]?.[srcToken.address];
|
|
692
|
+
if (options?.forceRpc || balanceFromBackend === undefined) {
|
|
693
|
+
const balanceUI = await getBalanceOf(
|
|
694
|
+
evmAddress,
|
|
695
|
+
srcToken.address,
|
|
696
|
+
srcChain?.publicRpcUrls[0],
|
|
697
|
+
);
|
|
698
|
+
balance = humanReadableToWei({
|
|
699
|
+
amount: balanceUI,
|
|
700
|
+
decimals: srcToken.decimals,
|
|
718
701
|
});
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
702
|
+
if (options?.forceRpc && balanceFromBackend !== undefined) {
|
|
703
|
+
// keep the backend cache in sync so token pickers and future
|
|
704
|
+
// non-forced refreshes see the fresh value
|
|
705
|
+
const chainId = srcChain.chainId;
|
|
706
|
+
const tokenAddress = srcToken.address;
|
|
707
|
+
const freshBalance = balance;
|
|
708
|
+
setTokenBalances((prev) => ({
|
|
709
|
+
...prev,
|
|
710
|
+
[chainId]: {
|
|
711
|
+
...prev[chainId],
|
|
712
|
+
[tokenAddress]: freshBalance,
|
|
713
|
+
},
|
|
714
|
+
}));
|
|
715
|
+
}
|
|
729
716
|
} else {
|
|
730
|
-
balance =
|
|
717
|
+
balance = balanceFromBackend;
|
|
718
|
+
}
|
|
719
|
+
} else if (srcChain?.ecosystem === Ecosystem.SOLANA && solanaAddress) {
|
|
720
|
+
const solanaPublicKey = new PublicKey(solanaAddress);
|
|
721
|
+
const connection = new Connection(srcChain.publicRpcUrls[0]!);
|
|
722
|
+
if (srcToken.address === SOLANA_NATIVE_TOKEN_ADDRESS.toBase58()) {
|
|
723
|
+
balance = new BigNumberJS(
|
|
724
|
+
await connection.getBalance(solanaPublicKey),
|
|
725
|
+
).toString();
|
|
726
|
+
} else {
|
|
727
|
+
const tokenAccounts = await connection.getParsedTokenAccountsByOwner(
|
|
728
|
+
solanaPublicKey,
|
|
729
|
+
{
|
|
730
|
+
programId: SOLANA_TOKEN_PROGRAM_ID,
|
|
731
|
+
},
|
|
732
|
+
);
|
|
733
|
+
const token2022Accounts =
|
|
734
|
+
await connection.getParsedTokenAccountsByOwner(solanaPublicKey, {
|
|
735
|
+
programId: SOLANA_TOKEN_2022_PROGRAM_ID,
|
|
736
|
+
});
|
|
737
|
+
const allTokenAccount = [
|
|
738
|
+
...tokenAccounts.value,
|
|
739
|
+
...token2022Accounts.value,
|
|
740
|
+
];
|
|
741
|
+
const tokenAccount = allTokenAccount.find(
|
|
742
|
+
(account) =>
|
|
743
|
+
account.account.data.parsed.info.mint === srcToken.address,
|
|
744
|
+
);
|
|
745
|
+
if (!tokenAccount) {
|
|
746
|
+
balance = "0";
|
|
747
|
+
} else {
|
|
748
|
+
balance = tokenAccount.account.data.parsed.info.tokenAmount.amount;
|
|
749
|
+
}
|
|
731
750
|
}
|
|
732
751
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
}
|
|
752
|
+
if (nonce !== refreshSelectedTokenBalanceNonce.current) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
737
755
|
|
|
738
|
-
|
|
756
|
+
setSrcTokenBalanceWei(balance);
|
|
739
757
|
|
|
740
|
-
|
|
741
|
-
|
|
758
|
+
setIsFetchingBalance(false);
|
|
759
|
+
},
|
|
760
|
+
[evmAddress, solanaAddress, srcChain, srcToken, tokenBalances],
|
|
761
|
+
);
|
|
742
762
|
// retrieves token details for a given token address and chain from supported tokens mapping. (including imported tokens)
|
|
743
763
|
const findTokenDataByAddressAndChain = useCallback(
|
|
744
764
|
(tokenAddress: string, chainId: string): Token | undefined => {
|
|
@@ -801,9 +821,16 @@ export const SwapProvider = ({
|
|
|
801
821
|
quoteRoute();
|
|
802
822
|
}, [quoteRoute]);
|
|
803
823
|
// calls refreshBalance to update source token balance on mount or when refreshBalance changes.
|
|
824
|
+
// when the connected wallet changed, force an RPC read — the cached backend
|
|
825
|
+
// balances still belong to the previous wallet until getBalances resolves.
|
|
804
826
|
useEffect(() => {
|
|
805
|
-
|
|
806
|
-
|
|
827
|
+
const walletAddresses = `${evmAddress ?? ""}:${solanaAddress ?? ""}`;
|
|
828
|
+
const walletChanged =
|
|
829
|
+
prevWalletAddresses.current !== undefined &&
|
|
830
|
+
prevWalletAddresses.current !== walletAddresses;
|
|
831
|
+
prevWalletAddresses.current = walletAddresses;
|
|
832
|
+
refreshBalance(walletChanged ? { forceRpc: true } : undefined);
|
|
833
|
+
}, [refreshBalance, evmAddress, solanaAddress]);
|
|
807
834
|
// fetches user all token balances when a wallet address is available and supported chains are loaded.
|
|
808
835
|
useEffect(() => {
|
|
809
836
|
let isCancelled = false;
|
package/src/utils/index.ts
CHANGED
|
@@ -77,6 +77,27 @@ export const resolveTokenAddress = (
|
|
|
77
77
|
?.address?.toLowerCase();
|
|
78
78
|
};
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Checks whether a transfer from `srcChain` can reach `dstChainId`,
|
|
82
|
+
* based on the chain-level support lists.
|
|
83
|
+
*/
|
|
84
|
+
export const isChainConnectionSupported = (
|
|
85
|
+
srcChain: Chain | undefined,
|
|
86
|
+
dstChainId: string | undefined,
|
|
87
|
+
bridgeUI: boolean,
|
|
88
|
+
): boolean => {
|
|
89
|
+
if (!srcChain || !dstChainId) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
if (srcChain.chainId === dstChainId) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
const supportedDst = bridgeUI
|
|
96
|
+
? srcChain.supportedDstForBridge
|
|
97
|
+
: srcChain.supportedDstForSwap;
|
|
98
|
+
return !!supportedDst?.includes(dstChainId);
|
|
99
|
+
};
|
|
100
|
+
|
|
80
101
|
export const sortChains = (chains: Chain[], disabledChainIds: string[]) =>
|
|
81
102
|
[...chains]
|
|
82
103
|
|
package/tailwind.config.js
CHANGED
|
@@ -96,10 +96,10 @@ export default {
|
|
|
96
96
|
x_modal: "var(--modal-width, 340px)",
|
|
97
97
|
},
|
|
98
98
|
width: {
|
|
99
|
-
x_modal: "var(--modal-width)",
|
|
99
|
+
x_modal: "var(--modal-width, 620px)",
|
|
100
100
|
},
|
|
101
101
|
maxWidth: {
|
|
102
|
-
x_modal: "var(--modal-width,
|
|
102
|
+
x_modal: "var(--modal-width, 620px)",
|
|
103
103
|
},
|
|
104
104
|
animation: {
|
|
105
105
|
"spin-slow": "spin 3s linear infinite",
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { DotGreenIcon } from "@src/assets/icons";
|
|
2
|
-
import { SwapPanelType } from "@src/components/Swap/SwapView";
|
|
3
|
-
import { useSwapContext } from "@src/context";
|
|
4
|
-
import useNetworks from "@src/hooks/networkManagement/useNetworks";
|
|
5
|
-
import { Chain } from "@src/models";
|
|
6
|
-
import { useMemo } from "react";
|
|
7
|
-
|
|
8
|
-
type Props = {
|
|
9
|
-
chain: Chain;
|
|
10
|
-
type: SwapPanelType;
|
|
11
|
-
disabled: boolean;
|
|
12
|
-
onClick: (chainId: string) => void;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const ChainItem = ({ chain, type, onClick, disabled }: Props) => {
|
|
16
|
-
const {
|
|
17
|
-
networks: { evm },
|
|
18
|
-
} = useNetworks();
|
|
19
|
-
|
|
20
|
-
const { srcChain, dstChain, bridgeUI } = useSwapContext();
|
|
21
|
-
|
|
22
|
-
const currentChainId = useMemo(
|
|
23
|
-
() => (type === "source" ? srcChain?.chainId : dstChain?.chainId),
|
|
24
|
-
[dstChain, srcChain, type],
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const connected = useMemo(
|
|
28
|
-
() => evm.signer && evm.chainId === chain.chainId,
|
|
29
|
-
[chain.chainId, evm.chainId, evm.signer],
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
const sameChainId = useMemo(() => {
|
|
33
|
-
if (!bridgeUI) {
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return type === "destination" ? srcChain?.chainId : dstChain?.chainId;
|
|
38
|
-
}, [bridgeUI, dstChain?.chainId, srcChain?.chainId, type]);
|
|
39
|
-
|
|
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
|
-
};
|
|
53
|
-
|
|
54
|
-
const tooltipText = getTooltipText();
|
|
55
|
-
|
|
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]"
|
|
78
|
-
/>
|
|
79
|
-
<p>{chain.displayName}</p>
|
|
80
|
-
</div>
|
|
81
|
-
|
|
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
|
-
)}
|
|
87
|
-
|
|
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>
|
|
95
|
-
</div>
|
|
96
|
-
);
|
|
97
|
-
};
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { CloseIcon, SearchIcon } from "@src/assets/icons";
|
|
2
|
-
import { useSwapContext } from "@src/context";
|
|
3
|
-
import { useMemo, useState, useRef, useEffect } from "react";
|
|
4
|
-
import { Virtuoso } from "react-virtuoso";
|
|
5
|
-
import { SwapPanelType } from "../../../../SwapView";
|
|
6
|
-
import { ChainItem } from "./ChainItem";
|
|
7
|
-
import { TextInput } from "@src/components";
|
|
8
|
-
|
|
9
|
-
type Props = {
|
|
10
|
-
type: SwapPanelType;
|
|
11
|
-
onClose: () => void;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const ChainPicker = ({ type, onClose }: Props) => {
|
|
15
|
-
const { setSrcChain, setDstChain, srcChainOptions, dstChainOptions } =
|
|
16
|
-
useSwapContext();
|
|
17
|
-
|
|
18
|
-
const [searchValue, setSearchValue] = useState("");
|
|
19
|
-
const chainSearchRef = useRef<HTMLInputElement | null>(null);
|
|
20
|
-
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
if (chainSearchRef.current) {
|
|
23
|
-
setTimeout(() => {
|
|
24
|
-
chainSearchRef.current?.focus();
|
|
25
|
-
}, 10);
|
|
26
|
-
}
|
|
27
|
-
}, []);
|
|
28
|
-
|
|
29
|
-
// search input filtering
|
|
30
|
-
const filteredChains = useMemo(() => {
|
|
31
|
-
const chains = type === "source" ? srcChainOptions : dstChainOptions;
|
|
32
|
-
if (!searchValue) return chains;
|
|
33
|
-
|
|
34
|
-
return chains.filter((chain) => {
|
|
35
|
-
const searchLower = searchValue.toLowerCase();
|
|
36
|
-
return (
|
|
37
|
-
chain.displayName.toLowerCase().includes(searchLower) ||
|
|
38
|
-
chain.chainId.toLowerCase().includes(searchLower)
|
|
39
|
-
);
|
|
40
|
-
});
|
|
41
|
-
}, [type, srcChainOptions, dstChainOptions, searchValue]);
|
|
42
|
-
|
|
43
|
-
const select = (selectedChainId: string) => {
|
|
44
|
-
const chain = filteredChains.find(
|
|
45
|
-
({ chainId }) => chainId === selectedChainId,
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
if (!chain) {
|
|
49
|
-
throw new Error(
|
|
50
|
-
`ChainPicker > selected chain id that is absent in chain options list.`,
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
type === "source" ? setSrcChain(chain) : setDstChain(chain);
|
|
55
|
-
onClose();
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<div className="flex flex-col h-full">
|
|
60
|
-
<div className="flex justify-between">
|
|
61
|
-
<div className="text-base/4 text-t_text_primary mb-4">{`Pick ${type} chain`}</div>
|
|
62
|
-
<div
|
|
63
|
-
className="w-4 h-4 fill-t_text_primary cursor-pointer"
|
|
64
|
-
onClick={onClose}
|
|
65
|
-
>
|
|
66
|
-
<CloseIcon />
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
|
|
70
|
-
<TextInput
|
|
71
|
-
ref={chainSearchRef}
|
|
72
|
-
inputIcon={
|
|
73
|
-
<div className="fill-t_text_primary">
|
|
74
|
-
<SearchIcon />
|
|
75
|
-
</div>
|
|
76
|
-
}
|
|
77
|
-
placeholder="Search chain name"
|
|
78
|
-
value={searchValue}
|
|
79
|
-
handleChange={setSearchValue}
|
|
80
|
-
/>
|
|
81
|
-
|
|
82
|
-
<div className="horizontal-separator mt-4" />
|
|
83
|
-
<div className="h-full pt-4">
|
|
84
|
-
{filteredChains.length ? (
|
|
85
|
-
<Virtuoso
|
|
86
|
-
style={{ height: "100%" }}
|
|
87
|
-
data={filteredChains}
|
|
88
|
-
itemContent={(_, chain) => (
|
|
89
|
-
<ChainItem
|
|
90
|
-
chain={chain}
|
|
91
|
-
type={type}
|
|
92
|
-
disabled={chain.disabled}
|
|
93
|
-
onClick={select}
|
|
94
|
-
/>
|
|
95
|
-
)}
|
|
96
|
-
/>
|
|
97
|
-
) : (
|
|
98
|
-
<div className="flex justify-center mt-4">No chain found.</div>
|
|
99
|
-
)}
|
|
100
|
-
</div>
|
|
101
|
-
</div>
|
|
102
|
-
);
|
|
103
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { ArrowDownIcon } from "@src/assets/icons";
|
|
2
|
-
import { Modal } from "@src/components/Modal";
|
|
3
|
-
import { useSwapContext } from "@src/context";
|
|
4
|
-
import { Chain } from "@src/models";
|
|
5
|
-
import { useMemo, useState } from "react";
|
|
6
|
-
import { SwapPanelType } from "../../../SwapView";
|
|
7
|
-
import { ChainPicker } from "./ChainPicker";
|
|
8
|
-
|
|
9
|
-
type Props = {
|
|
10
|
-
chain: Chain | undefined;
|
|
11
|
-
type: SwapPanelType;
|
|
12
|
-
className?: string;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const ChainPanel = ({ chain, type, className }: Props) => {
|
|
16
|
-
const { srcChainLocked, dstChainLocked } = useSwapContext();
|
|
17
|
-
|
|
18
|
-
const projectLockedDestinationChain = useMemo(
|
|
19
|
-
() => type === "destination" && dstChainLocked,
|
|
20
|
-
[type, dstChainLocked],
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
const projectLockedSourceChain = useMemo(
|
|
24
|
-
() => type === "source" && srcChainLocked,
|
|
25
|
-
[type, srcChainLocked],
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
const [chainPickerModalOpen, setChainPickerModalOpen] = useState(false);
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<>
|
|
32
|
-
{chainPickerModalOpen && (
|
|
33
|
-
<Modal onClose={() => setChainPickerModalOpen(false)}>
|
|
34
|
-
<ChainPicker
|
|
35
|
-
type={type}
|
|
36
|
-
onClose={() => setChainPickerModalOpen(false)}
|
|
37
|
-
/>
|
|
38
|
-
</Modal>
|
|
39
|
-
)}
|
|
40
|
-
|
|
41
|
-
<button
|
|
42
|
-
type="button"
|
|
43
|
-
disabled={projectLockedDestinationChain || projectLockedSourceChain}
|
|
44
|
-
onClick={() => setChainPickerModalOpen(true)}
|
|
45
|
-
className={`${className || ""}`}
|
|
46
|
-
>
|
|
47
|
-
<div className="flex justify-between items-center p-4 gap-8">
|
|
48
|
-
<div className="flex flex-col font-medium items-start">
|
|
49
|
-
<p className="text-xs opacity-60">
|
|
50
|
-
{type === "source" ? "From:" : "To:"}
|
|
51
|
-
</p>
|
|
52
|
-
<p className={`${chain ? "" : "opacity-60"}`}>
|
|
53
|
-
{chain ? chain.displayName : "Select"}
|
|
54
|
-
</p>
|
|
55
|
-
</div>
|
|
56
|
-
{!projectLockedDestinationChain && !projectLockedSourceChain && (
|
|
57
|
-
<div className="w-4 h-2 fill-t_text_primary">
|
|
58
|
-
<ArrowDownIcon />
|
|
59
|
-
</div>
|
|
60
|
-
)}
|
|
61
|
-
</div>
|
|
62
|
-
</button>
|
|
63
|
-
</>
|
|
64
|
-
);
|
|
65
|
-
};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { useSwapContext } from "@src/context";
|
|
2
|
-
import { weiToHumanReadable } from "@src/utils";
|
|
3
|
-
import { SwapPanelType } from "../../index";
|
|
4
|
-
|
|
5
|
-
type Props = {
|
|
6
|
-
type: SwapPanelType;
|
|
7
|
-
};
|
|
8
|
-
export const MaxPanel = ({ type }: Props) => {
|
|
9
|
-
const { srcToken, srcTokenBalanceWei, srcTokenBalanceInfo, setSrcValue } =
|
|
10
|
-
useSwapContext();
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<button
|
|
14
|
-
type="button"
|
|
15
|
-
className={`flex items-center w-16 justify-center p-4 gap-8 ${
|
|
16
|
-
!srcTokenBalanceInfo && "opacity-60"
|
|
17
|
-
} ${
|
|
18
|
-
type === "source" &&
|
|
19
|
-
"border-l border-solid border-t_text_primary border-opacity-10"
|
|
20
|
-
}`}
|
|
21
|
-
disabled={!srcTokenBalanceInfo}
|
|
22
|
-
onClick={() =>
|
|
23
|
-
setSrcValue(
|
|
24
|
-
weiToHumanReadable({
|
|
25
|
-
amount: srcTokenBalanceWei,
|
|
26
|
-
decimals: srcToken?.decimals || 18,
|
|
27
|
-
precisionFractionalPlaces: srcToken?.decimals || 18,
|
|
28
|
-
}),
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
>
|
|
32
|
-
{type === "source" && (
|
|
33
|
-
<p
|
|
34
|
-
className={`border-b border-solid border-t_text_primary ${
|
|
35
|
-
!srcTokenBalanceInfo && "border-opacity-60"
|
|
36
|
-
}`}
|
|
37
|
-
>
|
|
38
|
-
Max
|
|
39
|
-
</p>
|
|
40
|
-
)}
|
|
41
|
-
</button>
|
|
42
|
-
);
|
|
43
|
-
};
|
package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { TokenLogo } from "@src/components";
|
|
2
|
-
import { TokenOption } from "@src/models";
|
|
3
|
-
|
|
4
|
-
type Props = {
|
|
5
|
-
token: TokenOption;
|
|
6
|
-
selectedTokenAddress: string | undefined;
|
|
7
|
-
onClick: () => void;
|
|
8
|
-
};
|
|
9
|
-
export const QuickPickTokenItem = ({
|
|
10
|
-
token,
|
|
11
|
-
selectedTokenAddress,
|
|
12
|
-
onClick,
|
|
13
|
-
}: Props) => {
|
|
14
|
-
return (
|
|
15
|
-
<button
|
|
16
|
-
type="button"
|
|
17
|
-
className={`flex gap-2 py-2 pr-[14px] pl-2 items-center border border-solid border-t_text_primary border-opacity-10 rounded-3xl text-start hover:bg-t_bg_tertiary hover:bg-opacity-10 ${
|
|
18
|
-
token.address.toLowerCase() === selectedTokenAddress?.toLowerCase()
|
|
19
|
-
? "bg-t_bg_tertiary bg-opacity-10"
|
|
20
|
-
: "bg-t_bg_primary"
|
|
21
|
-
}`}
|
|
22
|
-
onClick={onClick}
|
|
23
|
-
>
|
|
24
|
-
<TokenLogo
|
|
25
|
-
token={token}
|
|
26
|
-
className="w-6 h-6"
|
|
27
|
-
generatedLogoClassName="w-6 h-6"
|
|
28
|
-
/>
|
|
29
|
-
<div className="flex flex-col gap-1 text-xs font-medium !leading-3">
|
|
30
|
-
<div className="text-t_text_primary">{token.name}</div>
|
|
31
|
-
<div className="text-t_text_primary text-opacity-50">
|
|
32
|
-
{token.symbol}
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
</button>
|
|
36
|
-
);
|
|
37
|
-
};
|