@xswap-link/sdk 0.0.13 → 0.1.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/.github/workflows/main.yml +2 -1
- package/.github/workflows/publish.yml +2 -1
- package/.prettierrc +7 -0
- package/CHANGELOG.md +27 -1
- package/README.md +23 -14
- package/dist/index.css +1108 -0
- package/dist/index.d.mts +212 -52
- package/dist/index.d.ts +212 -52
- package/dist/index.js +2184 -85
- package/dist/index.mjs +2148 -76
- package/nodemon.json +5 -0
- package/package.json +20 -3
- package/postcss.config.js +3 -0
- package/src/components/Alert/index.tsx +9 -0
- package/src/components/Skeleton/index.tsx +10 -0
- package/src/components/TxConfigForm/BalanceComponent.tsx +51 -0
- package/src/components/TxConfigForm/ChainListElement.tsx +36 -0
- package/src/components/TxConfigForm/Description.tsx +15 -0
- package/src/components/TxConfigForm/ErrorField.tsx +17 -0
- package/src/components/TxConfigForm/FeesDetails.tsx +105 -0
- package/src/components/TxConfigForm/Form.tsx +250 -0
- package/src/components/TxConfigForm/History.tsx +155 -0
- package/src/components/TxConfigForm/HistoryCard.tsx +209 -0
- package/src/components/TxConfigForm/Settings.tsx +137 -0
- package/src/components/TxConfigForm/Summary.tsx +57 -0
- package/src/components/TxConfigForm/SwapPanel.tsx +191 -0
- package/src/components/TxConfigForm/TokenPicker.tsx +171 -0
- package/src/components/TxConfigForm/TopBar.tsx +53 -0
- package/src/components/TxConfigForm/index.tsx +121 -0
- package/src/components/global.css +34 -0
- package/src/components/icons/ArrowDownIcon.tsx +16 -0
- package/src/components/icons/ArrowRightIcon.tsx +11 -0
- package/src/components/icons/ArrowUpRightIcon.tsx +11 -0
- package/src/components/icons/ChainlinkCCIPIcon.tsx +23 -0
- package/src/components/icons/CheckIcon.tsx +11 -0
- package/src/components/icons/ChevronDownIcon.tsx +15 -0
- package/src/components/icons/ChevronUpIcon.tsx +15 -0
- package/src/components/icons/CircularProgressIcon.tsx +24 -0
- package/src/components/icons/CloseIcon.tsx +15 -0
- package/src/components/icons/CoinsIcon.tsx +17 -0
- package/src/components/icons/DownArrorIcon.tsx +17 -0
- package/src/components/icons/HistoryIcon.tsx +16 -0
- package/src/components/icons/HourGlassIcon.tsx +11 -0
- package/src/components/icons/InfoIcon.tsx +13 -0
- package/src/components/icons/PercentageIcon.tsx +29 -0
- package/src/components/icons/SearchIcon.tsx +15 -0
- package/src/components/icons/SettingsIcon.tsx +16 -0
- package/src/components/icons/TimerIcon.tsx +15 -0
- package/src/components/icons/XMarkIcon.tsx +11 -0
- package/src/components/icons/XSwapBadgeIcon.tsx +23 -0
- package/src/components/icons/index.ts +20 -0
- package/src/components/index.ts +3 -0
- package/src/config/index.ts +1 -0
- package/src/config/wagmiConfig.ts +45 -0
- package/src/constants/index.ts +9 -5
- package/src/contracts/abi/BatchQuery.json +52 -0
- package/src/contracts/abi/index.ts +2 -0
- package/src/contracts/addresses.ts +34 -0
- package/src/contracts/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDebounce.tsx +21 -0
- package/src/index.ts +6 -0
- package/src/models/Addresses.ts +12 -0
- package/src/models/Route.ts +17 -5
- package/src/models/TokenData.ts +45 -0
- package/src/models/TransactionHistory.ts +48 -0
- package/src/models/XSwapConfig.ts +3 -0
- package/src/models/forms/TxConfigFormData.ts +8 -0
- package/src/models/forms/index.ts +1 -0
- package/src/models/index.ts +6 -6
- package/src/models/integrations/GenerateStakingCallsParams.ts +8 -0
- package/src/models/integrations/index.ts +1 -0
- package/src/models/payloads/GetPricesPayload.ts +4 -0
- package/src/models/payloads/GetRoutePayload.ts +1 -3
- package/src/models/payloads/GetSwapTxPayload.ts +8 -0
- package/src/models/payloads/index.ts +2 -0
- package/src/services/api.ts +46 -64
- package/src/services/index.ts +1 -0
- package/src/services/integrations/customCalls/index.ts +1 -0
- package/src/services/integrations/customCalls/staking.ts +83 -0
- package/src/services/integrations/index.ts +2 -0
- package/src/services/integrations/transactions.ts +30 -0
- package/src/utils/contracts.ts +153 -11
- package/src/utils/index.ts +49 -1
- package/src/utils/numbers.ts +47 -0
- package/src/utils/strings.ts +6 -0
- package/tailwind.config.js +19 -0
- package/test/api.test.ts +1 -1
- package/tsconfig.json +10 -1
- package/xswap.config.ts +18 -0
- package/index.ts +0 -5
- package/src/models/ApiOverrides.ts +0 -3
- package/src/models/Chain.ts +0 -20
- package/src/models/Prices.ts +0 -9
- package/src/models/Token.ts +0 -10
- package/src/models/XSwapFee.ts +0 -4
- package/src/models/XSwapFees.ts +0 -7
- package/src/utils/bigNumbers.ts +0 -7
package/nodemon.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xswap-link/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "JavaScript SDK for XSwap platform",
|
|
5
5
|
"homepage": "https://github.com/xswap-link/xswap-sdk",
|
|
6
6
|
"repository": {
|
|
@@ -20,8 +20,16 @@
|
|
|
20
20
|
"types": "dist/index.d.ts",
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@ethersproject/providers": "^5.7.2",
|
|
23
|
+
"@tanstack/react-query": "^5.35.5",
|
|
24
|
+
"@types/react": "18.2.0",
|
|
25
|
+
"@types/react-dom": "18.2.0",
|
|
23
26
|
"bignumber.js": "4.0.4",
|
|
24
|
-
"
|
|
27
|
+
"date-fns": "^3.6.0",
|
|
28
|
+
"ethers": "^5.7.2",
|
|
29
|
+
"react": "18.2.0",
|
|
30
|
+
"react-dom": "18.2.0",
|
|
31
|
+
"viem": "2.x",
|
|
32
|
+
"wagmi": "^2.8.5"
|
|
25
33
|
},
|
|
26
34
|
"devDependencies": {
|
|
27
35
|
"@changesets/cli": "^2.27.1",
|
|
@@ -33,13 +41,22 @@
|
|
|
33
41
|
"jest": "^29.7.0",
|
|
34
42
|
"jest-fetch": "^1.1.1",
|
|
35
43
|
"jest-fetch-mock": "^3.0.3",
|
|
44
|
+
"nodemon": "^3.1.0",
|
|
45
|
+
"tailwindcss": "^3.4.3",
|
|
36
46
|
"ts-jest": "^29.1.2",
|
|
37
47
|
"ts-node": "^10.9.2",
|
|
38
48
|
"tsup": "^8.0.2",
|
|
39
49
|
"typescript": "^5.3.3"
|
|
40
50
|
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@types/react": ">=16 || <=18",
|
|
53
|
+
"@types/react-dom": ">=16 || <=18",
|
|
54
|
+
"react": ">=16 || <=18",
|
|
55
|
+
"react-dom": ">=16 || <=18"
|
|
56
|
+
},
|
|
41
57
|
"scripts": {
|
|
42
|
-
"build": "tsup index.ts --format cjs,esm --dts",
|
|
58
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
59
|
+
"watch": "nodemon",
|
|
43
60
|
"release": "pnpm run build && changeset publish",
|
|
44
61
|
"lint": "tsc && eslint . --ext .ts",
|
|
45
62
|
"test": "jest"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { FC, useMemo } from "react";
|
|
2
|
+
import { Token, TokenBalances } from "@src/models";
|
|
3
|
+
import { weiToHumanReadable } from "@src/utils";
|
|
4
|
+
import BigNumber from "bignumber.js";
|
|
5
|
+
import { MINIMUM_DISPLAYED_TOKEN_AMOUNT } from "@src/constants";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
srcToken: Token | undefined;
|
|
9
|
+
balances: TokenBalances | undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const BalanceComponent: FC<Props> = ({ srcToken, balances }) => {
|
|
13
|
+
const balanceText = useMemo(() => {
|
|
14
|
+
if (!balances || !srcToken) return "0";
|
|
15
|
+
if (balances[srcToken.address]?.toString() === "0") return "0";
|
|
16
|
+
const fullHumanReadable = weiToHumanReadable({
|
|
17
|
+
amount: balances[srcToken.address]?.toString() || "0",
|
|
18
|
+
decimals: srcToken.decimals,
|
|
19
|
+
precisionFractionalPlaces: srcToken.decimals,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (
|
|
23
|
+
new BigNumber(fullHumanReadable).lt(
|
|
24
|
+
MINIMUM_DISPLAYED_TOKEN_AMOUNT.toString(),
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
return `<${MINIMUM_DISPLAYED_TOKEN_AMOUNT}`;
|
|
28
|
+
|
|
29
|
+
return weiToHumanReadable({
|
|
30
|
+
amount: balances[srcToken.address]?.toString() || "0",
|
|
31
|
+
decimals: srcToken.decimals,
|
|
32
|
+
precisionFractionalPlaces: 5,
|
|
33
|
+
});
|
|
34
|
+
}, [srcToken, balances]);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
Balance:{" "}
|
|
39
|
+
{srcToken && balances
|
|
40
|
+
? weiToHumanReadable({
|
|
41
|
+
amount: balances[srcToken.address]?.toString() || "0",
|
|
42
|
+
decimals: srcToken.decimals,
|
|
43
|
+
precisionFractionalPlaces: 4,
|
|
44
|
+
})
|
|
45
|
+
: 0}
|
|
46
|
+
<span className="bg-gradient-to-r from-x_blue_light to-x_blue_dark bg-clip-text text-transparent">
|
|
47
|
+
Max
|
|
48
|
+
</span>
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { Chain } from "@src/models";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
chain: Chain;
|
|
6
|
+
index: number;
|
|
7
|
+
length: number;
|
|
8
|
+
setSrcChain: (chain: Chain) => void;
|
|
9
|
+
setChainListShown: (x: boolean) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const ChainListElement: FC<Props> = ({
|
|
13
|
+
chain,
|
|
14
|
+
setSrcChain,
|
|
15
|
+
setChainListShown,
|
|
16
|
+
index,
|
|
17
|
+
length,
|
|
18
|
+
}) => {
|
|
19
|
+
return (
|
|
20
|
+
<div key={`${chain.ecosystem}-${chain.chainId}`}>
|
|
21
|
+
<li
|
|
22
|
+
className="bg-transparent border-none flex gap-1 items-center cursor-pointer py-2 w-full"
|
|
23
|
+
onClick={() => {
|
|
24
|
+
setSrcChain(chain);
|
|
25
|
+
setChainListShown(false);
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
<img width={12} height={12} src={chain.image} alt={chain.displayName} />
|
|
29
|
+
{chain.displayName}
|
|
30
|
+
</li>
|
|
31
|
+
{index !== length - 1 && (
|
|
32
|
+
<div className="h-px mx-2 bg-[rgba(255,255,255,0.15)]"></div>
|
|
33
|
+
)}
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React, { FC } from "react";
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const Description: FC<Props> = ({ description }) => {
|
|
8
|
+
return (
|
|
9
|
+
<div className="flex flex-col items-start rounded-lg px-4 py-2">
|
|
10
|
+
<div className="w-full flex gap-4 items-start justify-between text-xl">
|
|
11
|
+
{description}
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React, { FC } from "react";
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
error: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const ErrorField: FC<Props> = ({ error }) => {
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
className={`flex justify-center mb-1 items-center w-full rounded-2xl bg-x_error_background border border-solid ${
|
|
11
|
+
error.length > 0 ? "border-x_error_border" : "border-transparent"
|
|
12
|
+
}`}
|
|
13
|
+
>
|
|
14
|
+
{error}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { CoinsIcon, TimerIcon, ChevronUpIcon, ChevronDownIcon } from "../icons";
|
|
3
|
+
import { safeBigNumberFrom, weiToHumanReadable } from "@src/utils";
|
|
4
|
+
import { Route, Token } from "@src/models";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
route: Route | undefined;
|
|
8
|
+
isGettingRoute: boolean;
|
|
9
|
+
paymentToken: Token | undefined;
|
|
10
|
+
dstToken: Token | undefined;
|
|
11
|
+
expressChecked: boolean;
|
|
12
|
+
slippage: string | undefined;
|
|
13
|
+
feesDetailsShown: boolean;
|
|
14
|
+
setFeesDetailsShown: React.Dispatch<React.SetStateAction<boolean>>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const FeesDetails: FC<Props> = ({
|
|
18
|
+
isGettingRoute,
|
|
19
|
+
route,
|
|
20
|
+
paymentToken,
|
|
21
|
+
dstToken,
|
|
22
|
+
expressChecked,
|
|
23
|
+
slippage,
|
|
24
|
+
feesDetailsShown,
|
|
25
|
+
setFeesDetailsShown,
|
|
26
|
+
}) => {
|
|
27
|
+
return (
|
|
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 text-sm font-medium text-white opacity-60">
|
|
31
|
+
<CoinsIcon />
|
|
32
|
+
<div className="mr-1">Fees:</div>
|
|
33
|
+
{isGettingRoute ? (
|
|
34
|
+
<div className="bg-current rounded animate-pulse w-20 h-4" />
|
|
35
|
+
) : (
|
|
36
|
+
` ${weiToHumanReadable({
|
|
37
|
+
amount: safeBigNumberFrom(
|
|
38
|
+
route?.xSwapFees.xSwapFee.nativeFee || "0",
|
|
39
|
+
)
|
|
40
|
+
.add(safeBigNumberFrom(route?.xSwapFees.ccipFee || "0"))
|
|
41
|
+
.add(
|
|
42
|
+
safeBigNumberFrom(route?.xSwapFees.expressDeliveryFee || "0"),
|
|
43
|
+
)
|
|
44
|
+
.toString(),
|
|
45
|
+
decimals: 18,
|
|
46
|
+
precisionFractionalPlaces: 5,
|
|
47
|
+
})} ${paymentToken?.symbol}`
|
|
48
|
+
)}
|
|
49
|
+
</div>
|
|
50
|
+
<div className="flex gap-1">
|
|
51
|
+
<div
|
|
52
|
+
className={`flex gap-1 text-xs font-medium ${
|
|
53
|
+
expressChecked ? "text-x_green" : "text-white opacity-60"
|
|
54
|
+
}`}
|
|
55
|
+
>
|
|
56
|
+
<TimerIcon />
|
|
57
|
+
{expressChecked ? "Fast ~ 30sec " : "Normal ~ 30min"}
|
|
58
|
+
</div>
|
|
59
|
+
<div
|
|
60
|
+
onClick={() => setFeesDetailsShown((x) => !x)}
|
|
61
|
+
className="text-xs font-medium text-white opacity-60 cursor-pointer flex items-center"
|
|
62
|
+
>
|
|
63
|
+
{feesDetailsShown ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
{feesDetailsShown && (
|
|
68
|
+
<div className="flex w-full items-center justify-between ">
|
|
69
|
+
<div className="flex flex-col text-[10px] gap-1">
|
|
70
|
+
<div className="font-medium text-white opacity-60">
|
|
71
|
+
CCIP Fee:
|
|
72
|
+
{` ${weiToHumanReadable({
|
|
73
|
+
amount: route?.xSwapFees.ccipFee || "0",
|
|
74
|
+
decimals: 18,
|
|
75
|
+
precisionFractionalPlaces: 5,
|
|
76
|
+
})} ${paymentToken?.symbol}`}
|
|
77
|
+
</div>
|
|
78
|
+
<div className="font-medium text-white opacity-60">
|
|
79
|
+
Native Fee:
|
|
80
|
+
{` ${weiToHumanReadable({
|
|
81
|
+
amount: route?.xSwapFees.xSwapFee.nativeFee || "0",
|
|
82
|
+
decimals: 18,
|
|
83
|
+
precisionFractionalPlaces: 5,
|
|
84
|
+
})} ${paymentToken?.symbol}`}
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
<div className="flex flex-col text-[10px] gap-1">
|
|
88
|
+
<div className="font-medium text-white opacity-60">
|
|
89
|
+
Slippage: {`${slippage}%`}
|
|
90
|
+
</div>
|
|
91
|
+
<div className="font-medium text-white opacity-60">
|
|
92
|
+
Min amount out:{" "}
|
|
93
|
+
{weiToHumanReadable({
|
|
94
|
+
amount: route?.minAmountOut || "0",
|
|
95
|
+
decimals: dstToken?.decimals || 18,
|
|
96
|
+
precisionFractionalPlaces: 5,
|
|
97
|
+
})}{" "}
|
|
98
|
+
{dstToken?.symbol}
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import "@src/global.css";
|
|
2
|
+
import React, { FormEvent, useEffect, useState } from "react";
|
|
3
|
+
import { ethers } from "ethers";
|
|
4
|
+
import { useAccount, useSwitchChain } from "wagmi";
|
|
5
|
+
import { Chain, Route, Token, TokenBalances, TokenPrices } from "@src/models";
|
|
6
|
+
import { getPrices, getRoute } from "@src/services";
|
|
7
|
+
import { getBalances } from "@src/utils";
|
|
8
|
+
import { ROUTE_TIMEOUT_MS } from "@src/constants";
|
|
9
|
+
import { TxConfigFormProps } from "@src/components";
|
|
10
|
+
import { useDebounce } from "@src/hooks";
|
|
11
|
+
import { ADDRESSES } from "@src/contracts";
|
|
12
|
+
import { History } from "./History";
|
|
13
|
+
import { TopBar } from "./TopBar";
|
|
14
|
+
import { Settings } from "./Settings";
|
|
15
|
+
import { FeesDetails } from "./FeesDetails";
|
|
16
|
+
import { Summary } from "./Summary";
|
|
17
|
+
import { SwapPanel } from "./SwapPanel";
|
|
18
|
+
import { ErrorField } from "./ErrorField";
|
|
19
|
+
import { Description } from "./Description";
|
|
20
|
+
|
|
21
|
+
export const Form = ({
|
|
22
|
+
dstChainId,
|
|
23
|
+
dstTokenAddr,
|
|
24
|
+
customContractCalls,
|
|
25
|
+
desc,
|
|
26
|
+
supportedChains,
|
|
27
|
+
onSubmit,
|
|
28
|
+
}: TxConfigFormProps & {
|
|
29
|
+
onSubmit: (route: Route) => void;
|
|
30
|
+
}) => {
|
|
31
|
+
const [signer, setSigner] = useState<string | undefined>();
|
|
32
|
+
const [dstChain, setDstChain] = useState<Chain>();
|
|
33
|
+
const [dstToken, setDstToken] = useState<Token>();
|
|
34
|
+
const [srcChain, setSrcChain] = useState<Chain>();
|
|
35
|
+
const [srcToken, setSrcToken] = useState<Token>();
|
|
36
|
+
const [amount, setAmount] = useState<string>("");
|
|
37
|
+
const [paymentToken, setPaymentToken] = useState<Token>();
|
|
38
|
+
const [route, setRoute] = useState<Route>();
|
|
39
|
+
const [expressChecked, setExpressChecked] = useState(true);
|
|
40
|
+
const [historyTabShown, setHistoryTabShown] = useState(false);
|
|
41
|
+
const [isGettingRoute, setIsGettingRoute] = useState(false);
|
|
42
|
+
const [prices, setPrices] = useState<TokenPrices>();
|
|
43
|
+
const [balances, setBalances] = useState<TokenBalances>();
|
|
44
|
+
const [settingsShown, setSettingsShown] = useState(false);
|
|
45
|
+
const [formError, setFormError] = useState("");
|
|
46
|
+
const [slippage, setSlippage] = useState<string>("1.5");
|
|
47
|
+
const [feesDetailsShown, setFeesDetailsShown] = useState(false);
|
|
48
|
+
|
|
49
|
+
const debouncedAmount = useDebounce(amount, 1000);
|
|
50
|
+
const account = useAccount();
|
|
51
|
+
const { switchChainAsync } = useSwitchChain();
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
setSigner(account.address);
|
|
55
|
+
}, [account.address]);
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (
|
|
59
|
+
supportedChains.some(
|
|
60
|
+
({ chainId }) => chainId === account.chainId?.toString(),
|
|
61
|
+
)
|
|
62
|
+
) {
|
|
63
|
+
setSrcChain(
|
|
64
|
+
supportedChains.find(
|
|
65
|
+
({ chainId }) => chainId === account.chainId?.toString(),
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}, [account.chainId]);
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
setDstChain(supportedChains.find((chain) => chain.chainId === dstChainId));
|
|
73
|
+
}, [supportedChains, dstChainId]);
|
|
74
|
+
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
setDstToken(
|
|
77
|
+
dstChain?.tokens.find(
|
|
78
|
+
(token) => token.address.toLowerCase() === dstTokenAddr.toLowerCase(),
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
}, [dstChain]);
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (
|
|
85
|
+
srcChain &&
|
|
86
|
+
srcToken &&
|
|
87
|
+
dstChain &&
|
|
88
|
+
debouncedAmount &&
|
|
89
|
+
paymentToken &&
|
|
90
|
+
slippage
|
|
91
|
+
) {
|
|
92
|
+
setFormError("");
|
|
93
|
+
const timeout = setTimeout(() => {
|
|
94
|
+
setFormError("Getting Route is taking longer than usually");
|
|
95
|
+
}, ROUTE_TIMEOUT_MS);
|
|
96
|
+
setIsGettingRoute(true);
|
|
97
|
+
setFeesDetailsShown(false);
|
|
98
|
+
getRoute({
|
|
99
|
+
fromAmount: ethers.utils
|
|
100
|
+
.parseUnits(debouncedAmount, srcToken?.decimals)
|
|
101
|
+
.toString(),
|
|
102
|
+
fromAddress: signer || ADDRESSES[srcChain.chainId]!.FeeCollector,
|
|
103
|
+
fromChain: srcChain.chainId,
|
|
104
|
+
fromToken: srcToken.address,
|
|
105
|
+
toAddress: signer || ADDRESSES[dstChain.chainId]!.FeeCollector,
|
|
106
|
+
toChain: dstChainId,
|
|
107
|
+
toToken: dstTokenAddr,
|
|
108
|
+
paymentToken: paymentToken.address,
|
|
109
|
+
slippage: Number(slippage),
|
|
110
|
+
expressDelivery: expressChecked,
|
|
111
|
+
customContractCalls,
|
|
112
|
+
})
|
|
113
|
+
.then((response) => {
|
|
114
|
+
setRoute(response);
|
|
115
|
+
setFormError("");
|
|
116
|
+
})
|
|
117
|
+
.catch((err) => {
|
|
118
|
+
setFormError(err.message);
|
|
119
|
+
})
|
|
120
|
+
.finally(() => {
|
|
121
|
+
setIsGettingRoute(false);
|
|
122
|
+
clearTimeout(timeout);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}, [
|
|
126
|
+
signer,
|
|
127
|
+
srcChain,
|
|
128
|
+
srcToken,
|
|
129
|
+
debouncedAmount,
|
|
130
|
+
paymentToken,
|
|
131
|
+
slippage,
|
|
132
|
+
expressChecked,
|
|
133
|
+
]);
|
|
134
|
+
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (srcChain) {
|
|
137
|
+
setPaymentToken(
|
|
138
|
+
srcChain.tokens.find(
|
|
139
|
+
(token) =>
|
|
140
|
+
token.address.toLowerCase() ===
|
|
141
|
+
ethers.constants.AddressZero.toLowerCase(),
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}, [srcChain]);
|
|
146
|
+
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
setAmount("");
|
|
149
|
+
setFormError("");
|
|
150
|
+
}, [srcToken]);
|
|
151
|
+
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
setSrcToken(srcChain?.tokens[0]);
|
|
154
|
+
}, [srcChain]);
|
|
155
|
+
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (srcChain) {
|
|
158
|
+
getPrices({ chainId: srcChain.chainId, currency: "USD" }).then((prices) =>
|
|
159
|
+
setPrices(prices),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}, [srcChain]);
|
|
163
|
+
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (srcChain && signer) {
|
|
166
|
+
getBalances(srcChain, signer).then((balances) => setBalances(balances));
|
|
167
|
+
}
|
|
168
|
+
}, [srcChain, signer]);
|
|
169
|
+
|
|
170
|
+
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
|
|
171
|
+
event.preventDefault();
|
|
172
|
+
if (route) onSubmit(route);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const handleSwitchChain = async () => {
|
|
176
|
+
await switchChainAsync({ chainId: Number(srcChain?.chainId) });
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<form
|
|
181
|
+
className="flex flex-col gap-2 z-10 my-0 mx-auto p-4 rounded-3xl overflow-hidden font-light w-[360px] sm:w-[600px]"
|
|
182
|
+
onSubmit={handleSubmit}
|
|
183
|
+
>
|
|
184
|
+
<TopBar
|
|
185
|
+
signer={signer}
|
|
186
|
+
historyTabShown={historyTabShown}
|
|
187
|
+
setHistoryTabShown={setHistoryTabShown}
|
|
188
|
+
setSettingsShown={setSettingsShown}
|
|
189
|
+
/>
|
|
190
|
+
{settingsShown && (
|
|
191
|
+
<Settings
|
|
192
|
+
expressChecked={expressChecked}
|
|
193
|
+
setExpressChecked={setExpressChecked}
|
|
194
|
+
setSettingsShown={setSettingsShown}
|
|
195
|
+
slippage={slippage}
|
|
196
|
+
setSlippage={setSlippage}
|
|
197
|
+
/>
|
|
198
|
+
)}
|
|
199
|
+
{historyTabShown ? (
|
|
200
|
+
signer && <History signer={signer} supportedChains={supportedChains} />
|
|
201
|
+
) : (
|
|
202
|
+
<div className="flex flex-col gap-2">
|
|
203
|
+
{desc && <Description description={desc} />}
|
|
204
|
+
<SwapPanel
|
|
205
|
+
amount={amount}
|
|
206
|
+
setAmount={setAmount}
|
|
207
|
+
srcToken={srcToken}
|
|
208
|
+
setSrcToken={setSrcToken}
|
|
209
|
+
srcChain={srcChain}
|
|
210
|
+
signer={signer}
|
|
211
|
+
balances={balances}
|
|
212
|
+
prices={prices}
|
|
213
|
+
supportedChains={supportedChains}
|
|
214
|
+
setSrcChain={setSrcChain}
|
|
215
|
+
/>
|
|
216
|
+
<Summary
|
|
217
|
+
isGettingRoute={isGettingRoute}
|
|
218
|
+
amount={amount}
|
|
219
|
+
route={route}
|
|
220
|
+
dstToken={dstToken}
|
|
221
|
+
dstChain={dstChain}
|
|
222
|
+
/>
|
|
223
|
+
<FeesDetails
|
|
224
|
+
route={route}
|
|
225
|
+
isGettingRoute={isGettingRoute}
|
|
226
|
+
paymentToken={paymentToken}
|
|
227
|
+
dstToken={dstToken}
|
|
228
|
+
expressChecked={expressChecked}
|
|
229
|
+
slippage={slippage}
|
|
230
|
+
feesDetailsShown={feesDetailsShown}
|
|
231
|
+
setFeesDetailsShown={setFeesDetailsShown}
|
|
232
|
+
/>
|
|
233
|
+
{formError.length > 0 && <ErrorField error={formError} />}
|
|
234
|
+
{srcChain && srcChain.chainId !== account.chainId?.toString() ? (
|
|
235
|
+
<button type="button" onClick={handleSwitchChain}>
|
|
236
|
+
Switch chain
|
|
237
|
+
</button>
|
|
238
|
+
) : (
|
|
239
|
+
<button
|
|
240
|
+
type="submit"
|
|
241
|
+
disabled={!signer || !route || isGettingRoute}
|
|
242
|
+
>
|
|
243
|
+
Submit
|
|
244
|
+
</button>
|
|
245
|
+
)}
|
|
246
|
+
</div>
|
|
247
|
+
)}
|
|
248
|
+
</form>
|
|
249
|
+
);
|
|
250
|
+
};
|