@xswap-link/sdk 0.1.1 → 0.1.3
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 +20 -0
- package/dist/index.css +98 -39
- package/dist/index.d.mts +62 -157
- package/dist/index.d.ts +62 -157
- package/dist/index.js +962 -1923
- package/dist/index.mjs +919 -1887
- package/package.json +1 -1
- package/src/components/Skeleton/index.tsx +8 -5
- package/src/components/TxConfigForm/FeesDetails.tsx +5 -5
- package/src/components/TxConfigForm/Form.tsx +20 -14
- package/src/components/TxConfigForm/History.tsx +50 -101
- package/src/components/TxConfigForm/HistoryCard.tsx +22 -42
- package/src/components/TxConfigForm/Summary.tsx +57 -28
- package/src/components/TxConfigForm/SwapPanel.tsx +70 -77
- package/src/components/TxConfigForm/TokenPicker.tsx +69 -66
- package/src/components/TxConfigForm/TopBar.tsx +19 -19
- package/src/components/TxConfigForm/UsdPrice.tsx +41 -0
- package/src/components/TxConfigForm/index.tsx +1 -2
- package/src/components/TxHistoryButton/index.tsx +150 -0
- package/src/components/icons/ArrowLeftIcon.tsx +16 -0
- package/src/components/icons/ChevronUpIcon.tsx +1 -6
- package/src/components/icons/CircularProgressIcon.tsx +13 -15
- package/src/components/icons/XSwapLogo.tsx +98 -0
- package/src/components/icons/index.ts +2 -0
- package/src/components/index.ts +1 -0
- package/src/constants/index.ts +3 -2
- package/src/contracts/abi/index.ts +0 -2
- package/src/contracts/addresses.ts +6 -0
- package/src/models/Addresses.ts +1 -0
- package/src/models/TransactionHistory.ts +44 -29
- package/src/services/integrations/transactions.ts +166 -1
- package/src/utils/index.ts +7 -0
- package/tailwind.config.js +9 -0
- package/tsconfig.json +3 -7
- package/src/contracts/abi/XSwapRouter.json +0 -1242
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
type Props = {
|
|
4
|
+
width: string;
|
|
5
|
+
height: string;
|
|
6
|
+
other?: string;
|
|
5
7
|
};
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
export const Skeleton = ({ width, height }: Props) => {
|
|
10
|
+
return (
|
|
11
|
+
<div className={`bg-current rounded animate-pulse ${width} ${height}`} />
|
|
12
|
+
);
|
|
10
13
|
};
|
|
@@ -26,8 +26,8 @@ export const FeesDetails: FC<Props> = ({
|
|
|
26
26
|
}) => {
|
|
27
27
|
return (
|
|
28
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
|
|
29
|
+
<div className="flex w-full items-center justify-between text-xs sm:text-sm ">
|
|
30
|
+
<div className="flex items-center gap-1 font-medium text-white opacity-60">
|
|
31
31
|
<CoinsIcon />
|
|
32
32
|
<div className="mr-1">Fees:</div>
|
|
33
33
|
{isGettingRoute ? (
|
|
@@ -47,9 +47,9 @@ export const FeesDetails: FC<Props> = ({
|
|
|
47
47
|
})} ${paymentToken?.symbol}`
|
|
48
48
|
)}
|
|
49
49
|
</div>
|
|
50
|
-
<div className="flex gap-1">
|
|
50
|
+
<div className="flex gap-1 items-center">
|
|
51
51
|
<div
|
|
52
|
-
className={`flex gap-1
|
|
52
|
+
className={`flex gap-1 items-center font-medium ${
|
|
53
53
|
expressChecked ? "text-x_green" : "text-white opacity-60"
|
|
54
54
|
}`}
|
|
55
55
|
>
|
|
@@ -58,7 +58,7 @@ export const FeesDetails: FC<Props> = ({
|
|
|
58
58
|
</div>
|
|
59
59
|
<div
|
|
60
60
|
onClick={() => setFeesDetailsShown((x) => !x)}
|
|
61
|
-
className="
|
|
61
|
+
className="font-medium text-white opacity-60 cursor-pointer flex items-center w-[15px] h-[9px]"
|
|
62
62
|
>
|
|
63
63
|
{feesDetailsShown ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
|
64
64
|
</div>
|
|
@@ -17,6 +17,7 @@ import { Summary } from "./Summary";
|
|
|
17
17
|
import { SwapPanel } from "./SwapPanel";
|
|
18
18
|
import { ErrorField } from "./ErrorField";
|
|
19
19
|
import { Description } from "./Description";
|
|
20
|
+
import { DEFAULT_SOURCE_CHAIN_ID } from "@src/constants";
|
|
20
21
|
|
|
21
22
|
export const Form = ({
|
|
22
23
|
dstChainId,
|
|
@@ -55,17 +56,15 @@ export const Form = ({
|
|
|
55
56
|
}, [account.address]);
|
|
56
57
|
|
|
57
58
|
useEffect(() => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
setSrcChain(
|
|
59
|
+
const defaultChain = supportedChains.find(
|
|
60
|
+
({ chainId }) => chainId === account.chainId?.toString(),
|
|
61
|
+
);
|
|
62
|
+
setSrcChain(
|
|
63
|
+
defaultChain ??
|
|
64
64
|
supportedChains.find(
|
|
65
|
-
({ chainId }) => chainId ===
|
|
65
|
+
({ chainId }) => chainId === DEFAULT_SOURCE_CHAIN_ID,
|
|
66
66
|
),
|
|
67
|
-
|
|
68
|
-
}
|
|
67
|
+
);
|
|
69
68
|
}, [account.chainId]);
|
|
70
69
|
|
|
71
70
|
useEffect(() => {
|
|
@@ -95,9 +94,13 @@ export const Form = ({
|
|
|
95
94
|
}, ROUTE_TIMEOUT_MS);
|
|
96
95
|
setIsGettingRoute(true);
|
|
97
96
|
setFeesDetailsShown(false);
|
|
97
|
+
if (!srcToken.decimals)
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Configuration error: selected token ($${srcToken.symbol} ${srcToken.name}) has unknown decimals param.`,
|
|
100
|
+
);
|
|
98
101
|
getRoute({
|
|
99
102
|
fromAmount: ethers.utils
|
|
100
|
-
.parseUnits(debouncedAmount, srcToken
|
|
103
|
+
.parseUnits(debouncedAmount, srcToken.decimals)
|
|
101
104
|
.toString(),
|
|
102
105
|
fromAddress: signer || ADDRESSES[srcChain.chainId]!.FeeCollector,
|
|
103
106
|
fromChain: srcChain.chainId,
|
|
@@ -178,7 +181,7 @@ export const Form = ({
|
|
|
178
181
|
|
|
179
182
|
return (
|
|
180
183
|
<form
|
|
181
|
-
className="flex flex-col gap-2 z-10 my-0 mx-auto p-4 rounded-3xl overflow-hidden font-light w-
|
|
184
|
+
className="flex flex-col gap-2 z-10 my-0 mx-auto p-4 rounded-3xl overflow-hidden font-light w-x_mobile sm:w-x_desktop"
|
|
182
185
|
onSubmit={handleSubmit}
|
|
183
186
|
>
|
|
184
187
|
<TopBar
|
|
@@ -197,7 +200,7 @@ export const Form = ({
|
|
|
197
200
|
/>
|
|
198
201
|
)}
|
|
199
202
|
{historyTabShown ? (
|
|
200
|
-
|
|
203
|
+
<History signer={signer} supportedChains={supportedChains} />
|
|
201
204
|
) : (
|
|
202
205
|
<div className="flex flex-col gap-2">
|
|
203
206
|
{desc && <Description description={desc} />}
|
|
@@ -215,7 +218,6 @@ export const Form = ({
|
|
|
215
218
|
/>
|
|
216
219
|
<Summary
|
|
217
220
|
isGettingRoute={isGettingRoute}
|
|
218
|
-
amount={amount}
|
|
219
221
|
route={route}
|
|
220
222
|
dstToken={dstToken}
|
|
221
223
|
dstChain={dstChain}
|
|
@@ -232,7 +234,11 @@ export const Form = ({
|
|
|
232
234
|
/>
|
|
233
235
|
{formError.length > 0 && <ErrorField error={formError} />}
|
|
234
236
|
{srcChain && srcChain.chainId !== account.chainId?.toString() ? (
|
|
235
|
-
<button
|
|
237
|
+
<button
|
|
238
|
+
disabled={!signer}
|
|
239
|
+
type="button"
|
|
240
|
+
onClick={handleSwitchChain}
|
|
241
|
+
>
|
|
236
242
|
Switch chain
|
|
237
243
|
</button>
|
|
238
244
|
) : (
|
|
@@ -6,118 +6,60 @@ import BigNumberJS from "bignumber.js";
|
|
|
6
6
|
import { HistoryCard } from "./HistoryCard";
|
|
7
7
|
import { CircularProgressIcon } from "../icons";
|
|
8
8
|
|
|
9
|
-
const PENDING_TXS_LOCAL_STORAGE_KEY = "pending_transactions";
|
|
10
|
-
|
|
11
|
-
type LocalHistory = { [walletAddress: string]: Transaction[] };
|
|
12
|
-
|
|
13
9
|
interface Props {
|
|
14
|
-
signer: string;
|
|
10
|
+
signer: string | undefined;
|
|
15
11
|
supportedChains: Chain[];
|
|
16
12
|
}
|
|
17
13
|
|
|
18
14
|
export const History: FC<Props> = ({ signer, supportedChains }) => {
|
|
19
|
-
const [
|
|
20
|
-
// const [latestHistory, setLatestHistory] = useState<Transaction[]>();
|
|
15
|
+
const [fetchedHistory, setFetchedHistory] = useState<Transaction[]>();
|
|
21
16
|
const [historyLoadedOnce, setHistoryLoadedOnce] = useState(false);
|
|
22
17
|
|
|
23
|
-
const getLocalHistory = () => {
|
|
24
|
-
return JSON.parse(
|
|
25
|
-
localStorage.getItem(PENDING_TXS_LOCAL_STORAGE_KEY) || "{}",
|
|
26
|
-
) as LocalHistory;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const setLocalHistory = (data: LocalHistory) => {
|
|
30
|
-
localStorage.setItem(PENDING_TXS_LOCAL_STORAGE_KEY, JSON.stringify(data));
|
|
31
|
-
};
|
|
32
|
-
|
|
33
18
|
const fetchHistory = useCallback(async () => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
let status: TransactionStatus;
|
|
42
|
-
if (entry.failed) status = "REVERTED";
|
|
43
|
-
if (!!entry.target) {
|
|
44
|
-
status = "DONE";
|
|
45
|
-
} else {
|
|
46
|
-
status = "IN_PROGRESS";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const blockTimestampMs = new Date(entry.source.blockTime).getTime();
|
|
50
|
-
const estimatedDeliveryTimestamp = new BigNumberJS(
|
|
51
|
-
entry.source.valueForInstantCcipRecieve,
|
|
52
|
-
).gt(0)
|
|
53
|
-
? blockTimestampMs + EXPRESS_DELIVERY_TIME
|
|
54
|
-
: blockTimestampMs + DELIVERY_TIME;
|
|
55
|
-
|
|
56
|
-
fetchedTransactions.push({
|
|
57
|
-
hash: entry.source.transactionHash,
|
|
58
|
-
timestamp: blockTimestampMs / 1000,
|
|
59
|
-
sourceChainId: entry.source.blockchainId,
|
|
60
|
-
targetChainId: entry.source.targetBlockchainId,
|
|
61
|
-
amountWei: entry.source.tokenAmount,
|
|
62
|
-
tokenAddress: entry.source.tokenAddress,
|
|
63
|
-
tokenOutAddress:
|
|
64
|
-
entry.target?.tokenAddress || entry.source.tokenOutAddress,
|
|
65
|
-
tokenOutAmount:
|
|
66
|
-
entry.target?.tokenAmount || entry.source.estimatedAmountOut,
|
|
67
|
-
estimatedDeliveryTimestamp,
|
|
68
|
-
status,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const txHashToTxFromAPI: Record<string, Transaction> = {};
|
|
73
|
-
for (const transaction of fetchedTransactions) {
|
|
74
|
-
txHashToTxFromAPI[transaction.hash] = transaction;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const localHistory = getLocalHistory();
|
|
78
|
-
const newLocalHistory: Record<string, Transaction[]> = {};
|
|
79
|
-
|
|
80
|
-
for (const [walletAddress, transactions] of Object.entries(
|
|
81
|
-
localHistory,
|
|
82
|
-
)) {
|
|
83
|
-
if (walletAddress.toLowerCase() !== signer.toLowerCase()) {
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
const newLocalHistoryForWallet: Transaction[] = [];
|
|
87
|
-
|
|
88
|
-
for (const transaction of transactions) {
|
|
89
|
-
if (!txHashToTxFromAPI[transaction.hash]) {
|
|
90
|
-
// localStorage has fresher data.
|
|
91
|
-
fetchedTransactions.push(transaction);
|
|
92
|
-
newLocalHistoryForWallet.push(transaction);
|
|
19
|
+
if (signer) {
|
|
20
|
+
const downloadedHistory = await getHistory({ walletAddress: signer });
|
|
21
|
+
const fetchedTransactions: Transaction[] = [];
|
|
22
|
+
if (downloadedHistory) {
|
|
23
|
+
for (const entry of downloadedHistory.history) {
|
|
24
|
+
if (!entry.source) {
|
|
93
25
|
continue;
|
|
94
26
|
}
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// If we know on the frontend that the tx is done we should update backend result
|
|
102
|
-
txHashToTxFromAPI[transaction.hash]!.status = "DONE";
|
|
27
|
+
let status: TransactionStatus;
|
|
28
|
+
if (entry.failed) status = "REVERTED";
|
|
29
|
+
if (!!entry.target) {
|
|
30
|
+
status = "DONE";
|
|
31
|
+
} else {
|
|
32
|
+
status = "IN_PROGRESS";
|
|
103
33
|
}
|
|
104
34
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
35
|
+
const blockTimestampMs = new Date(entry.source.blockTime).getTime();
|
|
36
|
+
const estimatedDeliveryTimestamp = new BigNumberJS(
|
|
37
|
+
entry.source.valueForInstantCcipRecieve,
|
|
38
|
+
).gt(0)
|
|
39
|
+
? blockTimestampMs + EXPRESS_DELIVERY_TIME
|
|
40
|
+
: blockTimestampMs + DELIVERY_TIME;
|
|
41
|
+
|
|
42
|
+
fetchedTransactions.push({
|
|
43
|
+
hash: entry.source.transactionHash,
|
|
44
|
+
timestamp: blockTimestampMs / 1000,
|
|
45
|
+
sourceChainId: entry.source.blockchainId,
|
|
46
|
+
targetChainId: entry.source.targetBlockchainId,
|
|
47
|
+
amountWei: entry.source.tokenAmount,
|
|
48
|
+
tokenAddress: entry.source.tokenAddress,
|
|
49
|
+
tokenOutAddress:
|
|
50
|
+
entry.target?.tokenAddress || entry.source.tokenOutAddress,
|
|
51
|
+
tokenOutAmount:
|
|
52
|
+
entry.target?.tokenAmount || entry.source.estimatedAmountOut,
|
|
53
|
+
estimatedDeliveryTimestamp,
|
|
54
|
+
status,
|
|
55
|
+
});
|
|
112
56
|
}
|
|
113
57
|
|
|
114
|
-
|
|
58
|
+
setFetchedHistory(
|
|
59
|
+
fetchedTransactions.sort((a, b) => b.timestamp - a.timestamp),
|
|
60
|
+
);
|
|
61
|
+
setHistoryLoadedOnce(true);
|
|
115
62
|
}
|
|
116
|
-
setLocalHistory(newLocalHistory);
|
|
117
|
-
setMappedHistory(
|
|
118
|
-
fetchedTransactions.sort((a, b) => b.timestamp - a.timestamp),
|
|
119
|
-
);
|
|
120
|
-
setHistoryLoadedOnce(true);
|
|
121
63
|
}
|
|
122
64
|
}, [signer, getHistory]);
|
|
123
65
|
|
|
@@ -129,20 +71,27 @@ export const History: FC<Props> = ({ signer, supportedChains }) => {
|
|
|
129
71
|
return () => clearInterval(timer);
|
|
130
72
|
}, [signer, fetchHistory, getHistory, historyLoadedOnce]);
|
|
131
73
|
|
|
74
|
+
if (!signer)
|
|
75
|
+
return (
|
|
76
|
+
<div className="flex items-center justify-center w-full h-[30vh]">
|
|
77
|
+
Connect a wallet to browse history
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
|
|
132
81
|
return (
|
|
133
82
|
<div className="flex items-center justify-center w-full">
|
|
134
|
-
<div className="w-full h-
|
|
135
|
-
{
|
|
83
|
+
<div className="w-full h-96 overflow-scroll overflow-x-hidden">
|
|
84
|
+
{fetchedHistory?.length === 0 && historyLoadedOnce && (
|
|
136
85
|
<div className="w-full text-center py-4 px-0 text-[rgb(158,158,158)]">
|
|
137
86
|
Your history is empty...
|
|
138
87
|
</div>
|
|
139
88
|
)}
|
|
140
|
-
{!
|
|
89
|
+
{!fetchedHistory && !historyLoadedOnce && (
|
|
141
90
|
<div className="flex w-full h-full items-center justify-center">
|
|
142
91
|
<CircularProgressIcon />
|
|
143
92
|
</div>
|
|
144
93
|
)}
|
|
145
|
-
{
|
|
94
|
+
{fetchedHistory?.map((transaction, index) => (
|
|
146
95
|
<HistoryCard
|
|
147
96
|
key={index}
|
|
148
97
|
transaction={transaction}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FC, useCallback, useMemo } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { getDate } from "@src/utils";
|
|
3
3
|
import { Transaction, Chain, Token } from "@src/models";
|
|
4
4
|
import { deepMergeObjects, weiToHumanReadable } from "@src/utils";
|
|
5
5
|
import {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
HourGlassIcon,
|
|
10
10
|
XMarkIcon,
|
|
11
11
|
} from "@src/components/icons";
|
|
12
|
+
import { MINIMUM_DISPLAYED_TOKEN_AMOUNT } from "@src/constants";
|
|
12
13
|
|
|
13
14
|
interface Props {
|
|
14
15
|
transaction: Transaction;
|
|
@@ -16,11 +17,6 @@ interface Props {
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
19
|
-
const getDate = useCallback((blockTimestamp: number) => {
|
|
20
|
-
const date = new Date(blockTimestamp * 1000);
|
|
21
|
-
return format(date, "d MMM yyyy HH:mm:ss");
|
|
22
|
-
}, []);
|
|
23
|
-
|
|
24
20
|
const date = getDate(transaction.timestamp);
|
|
25
21
|
|
|
26
22
|
const supportedTokens: Record<string, Record<string, Token>> = useMemo(() => {
|
|
@@ -79,34 +75,25 @@ export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
|
79
75
|
);
|
|
80
76
|
|
|
81
77
|
return (
|
|
82
|
-
<div className="flex flex-col
|
|
83
|
-
<div className="flex items-center">
|
|
84
|
-
<div className="text-
|
|
85
|
-
<div className="flex
|
|
78
|
+
<div className="flex flex-col globalBorder rounded-xl bg-[rgb(15,15,15)] text-white text-xs sm:text-sm p-4 gap-3 mb-2">
|
|
79
|
+
<div className="flex w-full items-center justify-between">
|
|
80
|
+
<div className="text-sm sm:text-base">{date}</div>
|
|
81
|
+
<div className="flex items-center">
|
|
86
82
|
{transaction.status === "IN_PROGRESS" && (
|
|
87
83
|
<div className="flex items-center">
|
|
88
|
-
<div className="
|
|
89
|
-
<HourGlassIcon />
|
|
90
|
-
</div>
|
|
91
|
-
<div className="text-xs text-[rgb(250,200,100)]">In progress</div>
|
|
84
|
+
<div className="text-[rgb(250,200,100)]">In progress</div>
|
|
92
85
|
</div>
|
|
93
86
|
)}
|
|
94
87
|
|
|
95
88
|
{transaction.status === "DONE" && (
|
|
96
89
|
<div className="flex items-center">
|
|
97
|
-
<div className="
|
|
98
|
-
<CheckIcon />
|
|
99
|
-
</div>
|
|
100
|
-
<div className="text-xs text-[rgb(100,200,100)]">Done</div>
|
|
90
|
+
<div className="text-[rgb(100,200,100)]">Done</div>
|
|
101
91
|
</div>
|
|
102
92
|
)}
|
|
103
93
|
|
|
104
94
|
{transaction.status === "REVERTED" && (
|
|
105
95
|
<div className="flex items-center">
|
|
106
|
-
<div className="
|
|
107
|
-
<XMarkIcon />
|
|
108
|
-
</div>
|
|
109
|
-
<div className="text-xs text-[rgb(255,100,100)]">Reverted</div>
|
|
96
|
+
<div className="text-[rgb(255,100,100)]">Reverted</div>
|
|
110
97
|
</div>
|
|
111
98
|
)}
|
|
112
99
|
|
|
@@ -121,26 +108,24 @@ export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
|
121
108
|
className="ml-2 no-underline"
|
|
122
109
|
aria-label="Show the transaction in the chain explorer"
|
|
123
110
|
>
|
|
124
|
-
<div className="w-3.5 h-3.5
|
|
111
|
+
<div className="w-3.5 h-3.5">
|
|
125
112
|
<ArrowUpRightIcon />
|
|
126
113
|
</div>
|
|
127
114
|
</a>
|
|
128
115
|
</div>
|
|
129
116
|
</div>
|
|
130
|
-
<div className="flex flex-wrap gap-
|
|
131
|
-
<div className="flex
|
|
117
|
+
<div className="flex justify-between flex-wrap gap-2">
|
|
118
|
+
<div className="flex items-center">
|
|
132
119
|
<div className="flex items-center">
|
|
133
120
|
<img
|
|
134
121
|
src={sourceChainData?.image}
|
|
135
122
|
alt={`${sourceChainData?.name} logo`}
|
|
136
123
|
className="w-5 h-5 mr-1"
|
|
137
124
|
/>
|
|
138
|
-
<div
|
|
139
|
-
{sourceChainData?.displayName}
|
|
140
|
-
</div>
|
|
125
|
+
<div>{sourceChainData?.displayName}</div>
|
|
141
126
|
</div>
|
|
142
127
|
|
|
143
|
-
<div className="w-3.5 h-3.5
|
|
128
|
+
<div className="w-3.5 h-3.5 my-0 mx-1.5">
|
|
144
129
|
<ArrowRightIcon />
|
|
145
130
|
</div>
|
|
146
131
|
|
|
@@ -150,20 +135,17 @@ export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
|
150
135
|
alt={`${targetChainData?.name} logo`}
|
|
151
136
|
className="w-5 h-5 mr-1"
|
|
152
137
|
/>
|
|
153
|
-
<div
|
|
154
|
-
{targetChainData?.displayName}
|
|
155
|
-
</div>
|
|
138
|
+
<div>{targetChainData?.displayName}</div>
|
|
156
139
|
</div>
|
|
157
140
|
</div>
|
|
141
|
+
|
|
158
142
|
<div className="flex items-center mb-2 last:mb-0">
|
|
159
|
-
<div className="flex
|
|
143
|
+
<div className="flex items-center flex-wrap">
|
|
160
144
|
<div className="flex items-center">
|
|
161
|
-
{Number(transferredAmount) <
|
|
162
|
-
?
|
|
145
|
+
{Number(transferredAmount) < MINIMUM_DISPLAYED_TOKEN_AMOUNT
|
|
146
|
+
? `<${MINIMUM_DISPLAYED_TOKEN_AMOUNT}`
|
|
163
147
|
: transferredAmount}
|
|
164
|
-
<div className="
|
|
165
|
-
{tokenData?.symbol}
|
|
166
|
-
</div>
|
|
148
|
+
<div className="ml-1">{tokenData?.symbol}</div>
|
|
167
149
|
{tokenData?.image ? (
|
|
168
150
|
<img
|
|
169
151
|
src={tokenData?.image}
|
|
@@ -178,14 +160,12 @@ export const HistoryCard: FC<Props> = ({ transaction, supportedChains }) => {
|
|
|
178
160
|
</div>
|
|
179
161
|
{transaction.tokenOutAddress && (
|
|
180
162
|
<>
|
|
181
|
-
<div className="w-3.5 h-3.5
|
|
163
|
+
<div className="w-3.5 h-3.5 my-0 mx-1.5">
|
|
182
164
|
<ArrowRightIcon />
|
|
183
165
|
</div>
|
|
184
166
|
<div className="flex items-center">
|
|
185
167
|
{Number(receivedAmount) < 0.0001 ? "<0.0001" : receivedAmount}
|
|
186
|
-
<div className="
|
|
187
|
-
{tokenOutData?.symbol}
|
|
188
|
-
</div>
|
|
168
|
+
<div className="ml-1">{tokenOutData?.symbol}</div>
|
|
189
169
|
|
|
190
170
|
{tokenOutData?.image ? (
|
|
191
171
|
<img
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { FC } from "react";
|
|
1
|
+
import React, { FC, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { weiToHumanReadable } from "@src/utils";
|
|
3
|
-
import { Chain, Route, Token } from "@src/models";
|
|
3
|
+
import { Chain, Route, Token, TokenPrices } from "@src/models";
|
|
4
4
|
import { ArrowDownIcon } from "../icons";
|
|
5
|
+
import { UsdPrice } from "@src/components/TxConfigForm/UsdPrice";
|
|
6
|
+
import { getPrices } from "@src/services";
|
|
7
|
+
import { Skeleton } from "@src/components";
|
|
5
8
|
|
|
6
9
|
interface Props {
|
|
7
10
|
isGettingRoute: boolean;
|
|
8
|
-
amount: string;
|
|
9
11
|
route: Route | undefined;
|
|
10
12
|
dstToken: Token | undefined;
|
|
11
13
|
dstChain: Chain | undefined;
|
|
@@ -13,40 +15,67 @@ interface Props {
|
|
|
13
15
|
|
|
14
16
|
export const Summary: FC<Props> = ({
|
|
15
17
|
isGettingRoute,
|
|
16
|
-
amount,
|
|
17
18
|
route,
|
|
18
19
|
dstToken,
|
|
19
20
|
dstChain,
|
|
20
21
|
}) => {
|
|
22
|
+
const [prices, setPrices] = useState<TokenPrices>();
|
|
23
|
+
|
|
24
|
+
const amountReadable = useMemo(
|
|
25
|
+
() =>
|
|
26
|
+
weiToHumanReadable({
|
|
27
|
+
amount: route?.estAmountOut || "0",
|
|
28
|
+
decimals: dstToken?.decimals || 18,
|
|
29
|
+
precisionFractionalPlaces: 5,
|
|
30
|
+
}),
|
|
31
|
+
[route, dstToken],
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (dstChain) {
|
|
36
|
+
getPrices({ chainId: dstChain.chainId, currency: "USD" }).then((prices) =>
|
|
37
|
+
setPrices(prices),
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}, [dstChain]);
|
|
41
|
+
|
|
21
42
|
return (
|
|
22
|
-
<div className="flex
|
|
23
|
-
<div className="flex
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<
|
|
43
|
+
<div className="flex flex-col globalBorder rounded-lg bg-[rgba(15,15,15,1)] p-4 relative">
|
|
44
|
+
<div className="flex justify-between">
|
|
45
|
+
<div className="flex flex-col gap-1">
|
|
46
|
+
<p className="text-[rgba(255,255,255,0.6)] text-sm">You receive</p>
|
|
47
|
+
{isGettingRoute ? (
|
|
48
|
+
<Skeleton
|
|
49
|
+
width="w-[100px]"
|
|
50
|
+
height="h-[36px]"
|
|
51
|
+
other="sm:w-[190px]"
|
|
52
|
+
/>
|
|
53
|
+
) : (
|
|
54
|
+
<div className="flex gap-2 items-center text-white text-xl sm:text-3xl">
|
|
55
|
+
{amountReadable}
|
|
56
|
+
<div className="w-4 sm:w-6 h-4 sm:h-6">
|
|
57
|
+
<img src={dstToken?.image} alt={dstToken?.name} />
|
|
58
|
+
</div>
|
|
59
|
+
<p className="text-base sm:text-xl">{dstToken?.symbol}</p>
|
|
36
60
|
</div>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<
|
|
61
|
+
)}
|
|
62
|
+
</div>
|
|
63
|
+
<div className="flex flex-col gap-1 text-sm">
|
|
64
|
+
<p className="text-[rgba(255,255,255,0.6)] text-right">on chain:</p>
|
|
65
|
+
<div className="flex items-center gap-1 text-white">
|
|
66
|
+
<div className="w-4 h-4">
|
|
67
|
+
<img src={dstChain?.image} alt={dstChain?.name} />
|
|
68
|
+
</div>
|
|
69
|
+
<div>{dstChain?.displayName}</div>
|
|
46
70
|
</div>
|
|
47
|
-
<div>{dstChain?.displayName}</div>
|
|
48
71
|
</div>
|
|
49
72
|
</div>
|
|
73
|
+
<UsdPrice
|
|
74
|
+
prices={prices}
|
|
75
|
+
token={dstToken}
|
|
76
|
+
amount={amountReadable}
|
|
77
|
+
loading={isGettingRoute}
|
|
78
|
+
/>
|
|
50
79
|
<div className="absolute right-[50%] top-0 translate-x-1/2 translate-y-[-60%] globalBorder rounded-xl p-[5px] bg-[rgba(15,15,15,1)]">
|
|
51
80
|
<div className=" flex items-center justify-center rounded-lg w-8 h-8 bg-gradient-to-l from-[rgba(54,129,198,1)] to-[rgba(43,74,157,1)] ">
|
|
52
81
|
<ArrowDownIcon />
|