@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.
Files changed (35) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/index.css +98 -39
  3. package/dist/index.d.mts +62 -157
  4. package/dist/index.d.ts +62 -157
  5. package/dist/index.js +962 -1923
  6. package/dist/index.mjs +919 -1887
  7. package/package.json +1 -1
  8. package/src/components/Skeleton/index.tsx +8 -5
  9. package/src/components/TxConfigForm/FeesDetails.tsx +5 -5
  10. package/src/components/TxConfigForm/Form.tsx +20 -14
  11. package/src/components/TxConfigForm/History.tsx +50 -101
  12. package/src/components/TxConfigForm/HistoryCard.tsx +22 -42
  13. package/src/components/TxConfigForm/Summary.tsx +57 -28
  14. package/src/components/TxConfigForm/SwapPanel.tsx +70 -77
  15. package/src/components/TxConfigForm/TokenPicker.tsx +69 -66
  16. package/src/components/TxConfigForm/TopBar.tsx +19 -19
  17. package/src/components/TxConfigForm/UsdPrice.tsx +41 -0
  18. package/src/components/TxConfigForm/index.tsx +1 -2
  19. package/src/components/TxHistoryButton/index.tsx +150 -0
  20. package/src/components/icons/ArrowLeftIcon.tsx +16 -0
  21. package/src/components/icons/ChevronUpIcon.tsx +1 -6
  22. package/src/components/icons/CircularProgressIcon.tsx +13 -15
  23. package/src/components/icons/XSwapLogo.tsx +98 -0
  24. package/src/components/icons/index.ts +2 -0
  25. package/src/components/index.ts +1 -0
  26. package/src/constants/index.ts +3 -2
  27. package/src/contracts/abi/index.ts +0 -2
  28. package/src/contracts/addresses.ts +6 -0
  29. package/src/models/Addresses.ts +1 -0
  30. package/src/models/TransactionHistory.ts +44 -29
  31. package/src/services/integrations/transactions.ts +166 -1
  32. package/src/utils/index.ts +7 -0
  33. package/tailwind.config.js +9 -0
  34. package/tsconfig.json +3 -7
  35. package/src/contracts/abi/XSwapRouter.json +0 -1242
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xswap-link/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "JavaScript SDK for XSwap platform",
5
5
  "homepage": "https://github.com/xswap-link/xswap-sdk",
6
6
  "repository": {
@@ -1,10 +1,13 @@
1
1
  import React from "react";
2
2
 
3
- export const Skeleton = ({ w, h }: Style) => {
4
- return <div className={`bg-current rounded animate-pulse ${w} ${h}`} />;
3
+ type Props = {
4
+ width: string;
5
+ height: string;
6
+ other?: string;
5
7
  };
6
8
 
7
- type Style = {
8
- w: string;
9
- h: string;
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 text-sm font-medium text-white opacity-60">
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 text-xs font-medium ${
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="text-xs font-medium text-white opacity-60 cursor-pointer flex items-center"
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
- if (
59
- supportedChains.some(
60
- ({ chainId }) => chainId === account.chainId?.toString(),
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 === account.chainId?.toString(),
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?.decimals)
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-[360px] sm:w-[600px]"
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
- signer && <History signer={signer} supportedChains={supportedChains} />
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 type="button" onClick={handleSwitchChain}>
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 [mappedHistory, setMappedHistory] = useState<Transaction[]>();
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
- const downloadedHistory = await getHistory({ walletAddress: signer });
35
- const fetchedTransactions: Transaction[] = [];
36
- if (downloadedHistory) {
37
- for (const entry of downloadedHistory.history) {
38
- if (!entry.source) {
39
- continue;
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
- txHashToTxFromAPI[transaction.hash] &&
98
- transaction.status === "DONE" &&
99
- txHashToTxFromAPI[transaction.hash]?.status === "IN_PROGRESS"
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
- if (
106
- txHashToTxFromAPI[transaction.hash]?.status === "DONE" ||
107
- txHashToTxFromAPI[transaction.hash]?.status === "REVERTED"
108
- ) {
109
- // API has the same or fresher data.
110
- continue;
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
- newLocalHistory[walletAddress.toLowerCase()] = newLocalHistoryForWallet;
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-[50vh] overflow-scroll overflow-x-hidden">
135
- {mappedHistory?.length === 0 && historyLoadedOnce && (
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
- {!mappedHistory && !historyLoadedOnce && (
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
- {mappedHistory?.map((transaction, index) => (
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 { format } from "date-fns";
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 border border-solid border-[rgba(255,255,255,0.1)] rounded-xl bg-[rgb(15,15,15)] p-2 gap-4 mb-2">
83
- <div className="flex items-center">
84
- <div className="text-[rgba(255,255,255,0.6)] text-xs">{date}</div>
85
- <div className="flex flex-grow justify-end items-center">
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="w-3.5 h-3.5 mr-1 text-[rgb(250,200,100)]">
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="w-3.5 h-3.5 mr-1 text-[rgb(100,200,100)]">
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="w-4 h-4 mr-1 text-[rgb(255,100,100)]">
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 text-[rgba(255,255,255,0.6)]">
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-8">
131
- <div className="flex flex-grow items-center">
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 className="text-xs text-[rgba(255,255,255,0.6)]">
139
- {sourceChainData?.displayName}
140
- </div>
125
+ <div>{sourceChainData?.displayName}</div>
141
126
  </div>
142
127
 
143
- <div className="w-3.5 h-3.5 text-[rgba(255,255,255,0.6)] my-0 mx-1.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 className="text-xs text-[rgba(255,255,255,0.6)]">
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 flex-1 items-center flex-wrap text-xs text-[rgba(255,255,255,0.6)]">
143
+ <div className="flex items-center flex-wrap">
160
144
  <div className="flex items-center">
161
- {Number(transferredAmount) < 0.0001
162
- ? "<0.0001"
145
+ {Number(transferredAmount) < MINIMUM_DISPLAYED_TOKEN_AMOUNT
146
+ ? `<${MINIMUM_DISPLAYED_TOKEN_AMOUNT}`
163
147
  : transferredAmount}
164
- <div className="text-xs ml-1 text-rgba(255,255,255,0.6)">
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 text-[rgba(255,255,255,0.6)] my-0 mx-1.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="text-xs ml-1 text-[rgba(255,255,255,0.6)]">
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 justify-between globalBorder rounded-lg bg-[rgba(15,15,15,1)] p-4 relative">
23
- <div className="flex flex-col gap-2">
24
- <p className="text-[rgba(255,255,255,0.6)] text-sm">You receive</p>
25
- {isGettingRoute && amount.length > 0 ? (
26
- <div className="bg-current rounded animate-pulse w-[190px] h-7" />
27
- ) : (
28
- <div className="flex gap-2 items-center text-white text-2xl">
29
- {weiToHumanReadable({
30
- amount: route?.estAmountOut || "0",
31
- decimals: dstToken?.decimals || 18,
32
- precisionFractionalPlaces: 5,
33
- })}
34
- <div className="w-6 h-6">
35
- <img src={dstToken?.image} alt={dstToken?.name} />
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
- <p>{dstToken?.symbol}</p>
38
- </div>
39
- )}
40
- </div>
41
- <div className="flex flex-col gap-1 text-sm">
42
- <p className="text-[rgba(255,255,255,0.6)] text-right">on chain:</p>
43
- <div className="flex gap-1 text-white">
44
- <div className="w-4 h-4">
45
- <img src={dstChain?.image} alt={dstChain?.name} />
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 />