@ensofinance/checkout-widget 0.0.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.
Files changed (128) hide show
  1. package/dist/checkout-widget.es.js +52889 -0
  2. package/dist/checkout-widget.es.js.map +1 -0
  3. package/dist/checkout-widget.umd.js +203 -0
  4. package/dist/checkout-widget.umd.js.map +1 -0
  5. package/dist/index.d.ts +23 -0
  6. package/enso-api.yaml +1982 -0
  7. package/orval.config.ts +25 -0
  8. package/package.json +79 -0
  9. package/src/assets/BinanceBadge.svg +4 -0
  10. package/src/assets/CoinbaseIcon.svg +4 -0
  11. package/src/assets/USD Coin (USDC).svg +5 -0
  12. package/src/assets/avecIcon.svg +5 -0
  13. package/src/assets/base.webp +0 -0
  14. package/src/assets/depositIcon.svg +6 -0
  15. package/src/assets/eth.webp +0 -0
  16. package/src/assets/ethMainnetIcon.svg +10 -0
  17. package/src/assets/fail.svg +5 -0
  18. package/src/assets/kraken.png +0 -0
  19. package/src/assets/logo.svg +10 -0
  20. package/src/assets/mastercard.png +0 -0
  21. package/src/assets/metamask.png +0 -0
  22. package/src/assets/rabby.png +0 -0
  23. package/src/assets/success.svg +4 -0
  24. package/src/assets/usdc.webp +0 -0
  25. package/src/assets/usdt.webp +0 -0
  26. package/src/assets/visa.png +0 -0
  27. package/src/assets/visa.webp +0 -0
  28. package/src/components/BridgeFee.tsx +58 -0
  29. package/src/components/ChakraProvider.tsx +372 -0
  30. package/src/components/Checkout.tsx +127 -0
  31. package/src/components/CheckoutModal.tsx +22 -0
  32. package/src/components/CircleTimer.tsx +66 -0
  33. package/src/components/CurrencySwapDisplay.tsx +153 -0
  34. package/src/components/DepositProcessing.tsx +116 -0
  35. package/src/components/ExchangeConfirmSecurity.tsx +110 -0
  36. package/src/components/QuoteParameters.tsx +341 -0
  37. package/src/components/TransactionDetailRow.tsx +124 -0
  38. package/src/components/cards/AssetCard.tsx +167 -0
  39. package/src/components/cards/ExchangeCard.tsx +53 -0
  40. package/src/components/cards/OptionCard.tsx +59 -0
  41. package/src/components/cards/WalletCard.tsx +99 -0
  42. package/src/components/cards/index.ts +6 -0
  43. package/src/components/modal.tsx +83 -0
  44. package/src/components/steps/ExchangeFlow.tsx +1402 -0
  45. package/src/components/steps/InitialStep.tsx +169 -0
  46. package/src/components/steps/QuoteStep.tsx +121 -0
  47. package/src/components/steps/WalletAmountStep.tsx +258 -0
  48. package/src/components/steps/WalletConfirmStep.tsx +404 -0
  49. package/src/components/steps/WalletTokenStep.tsx +128 -0
  50. package/src/components/ui/index.tsx +394 -0
  51. package/src/components/ui/styled.tsx +85 -0
  52. package/src/components/ui/toaster.tsx +43 -0
  53. package/src/components/ui/tooltip.tsx +46 -0
  54. package/src/enso-api/api.ts +173 -0
  55. package/src/enso-api/custom-instance.ts +35 -0
  56. package/src/enso-api/index.ts +5119 -0
  57. package/src/enso-api/model/action.ts +17 -0
  58. package/src/enso-api/model/actionAction.ts +52 -0
  59. package/src/enso-api/model/actionInputs.ts +12 -0
  60. package/src/enso-api/model/actionToBundle.ts +19 -0
  61. package/src/enso-api/model/actionToBundleAction.ts +53 -0
  62. package/src/enso-api/model/actionToBundleArgs.ts +12 -0
  63. package/src/enso-api/model/bundleControllerBundleShortcutTransactionParams.ts +53 -0
  64. package/src/enso-api/model/bundleControllerBundleShortcutTransactionRoutingStrategy.ts +23 -0
  65. package/src/enso-api/model/bundleShortcutTransaction.ts +35 -0
  66. package/src/enso-api/model/bundleShortcutTransactionAmountsOut.ts +15 -0
  67. package/src/enso-api/model/bundleShortcutTransactionFeeAmount.ts +12 -0
  68. package/src/enso-api/model/connectedNetwork.ts +16 -0
  69. package/src/enso-api/model/hop.ts +24 -0
  70. package/src/enso-api/model/hopArgs.ts +12 -0
  71. package/src/enso-api/model/index.ts +70 -0
  72. package/src/enso-api/model/iporControllerIporShortcutTransactionParams.ts +21 -0
  73. package/src/enso-api/model/iporShortcutInput.ts +33 -0
  74. package/src/enso-api/model/iporShortcutTransaction.ts +22 -0
  75. package/src/enso-api/model/lZDestinationTokenData.ts +19 -0
  76. package/src/enso-api/model/lZPoolLookupResponse.ts +26 -0
  77. package/src/enso-api/model/layerZeroControllerGetPoolAddressParams.ts +29 -0
  78. package/src/enso-api/model/network.ts +15 -0
  79. package/src/enso-api/model/networksControllerNetworksParams.ts +21 -0
  80. package/src/enso-api/model/nonTokenizedControllerTokens200.ts +15 -0
  81. package/src/enso-api/model/nonTokenizedControllerTokens200AllOf.ts +16 -0
  82. package/src/enso-api/model/nonTokenizedControllerTokensParams.ts +41 -0
  83. package/src/enso-api/model/nonTokenizedModel.ts +27 -0
  84. package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionParams.ts +64 -0
  85. package/src/enso-api/model/nontokenizedControllerRouteNontokenizedShorcutTransactionRoutingStrategy.ts +22 -0
  86. package/src/enso-api/model/paginatedResult.ts +16 -0
  87. package/src/enso-api/model/paginationMeta.ts +27 -0
  88. package/src/enso-api/model/positionModel.ts +77 -0
  89. package/src/enso-api/model/price.ts +20 -0
  90. package/src/enso-api/model/pricesControllerGetPricesParams.ts +17 -0
  91. package/src/enso-api/model/project.ts +15 -0
  92. package/src/enso-api/model/protocol.ts +15 -0
  93. package/src/enso-api/model/protocolModel.ts +26 -0
  94. package/src/enso-api/model/protocolsControllerFindAllParams.ts +21 -0
  95. package/src/enso-api/model/routeShortcutTransaction.ts +33 -0
  96. package/src/enso-api/model/routeShortcutVariableInputs.ts +68 -0
  97. package/src/enso-api/model/routeShortcutVariableInputsRoutingStrategy.ts +27 -0
  98. package/src/enso-api/model/routeShortcutVariableInputsVariableEstimates.ts +14 -0
  99. package/src/enso-api/model/routerControllerRouteShortcutTransactionParams.ts +91 -0
  100. package/src/enso-api/model/routerControllerRouteShortcutTransactionRoutingStrategy.ts +23 -0
  101. package/src/enso-api/model/standard.ts +18 -0
  102. package/src/enso-api/model/standardAction.ts +20 -0
  103. package/src/enso-api/model/standardActionAction.ts +53 -0
  104. package/src/enso-api/model/tokenModel.ts +36 -0
  105. package/src/enso-api/model/tokensControllerTokens200.ts +15 -0
  106. package/src/enso-api/model/tokensControllerTokens200AllOf.ts +16 -0
  107. package/src/enso-api/model/tokensControllerTokensParams.ts +91 -0
  108. package/src/enso-api/model/tokensControllerTokensType.ts +19 -0
  109. package/src/enso-api/model/transaction.ts +17 -0
  110. package/src/enso-api/model/userOperation.ts +28 -0
  111. package/src/enso-api/model/walletApproveTransaction.ts +24 -0
  112. package/src/enso-api/model/walletApproveTransactionTx.ts +15 -0
  113. package/src/enso-api/model/walletBalance.ts +29 -0
  114. package/src/enso-api/model/walletControllerCreateApproveTransactionParams.ts +35 -0
  115. package/src/enso-api/model/walletControllerCreateApproveTransactionRoutingStrategy.ts +23 -0
  116. package/src/enso-api/model/walletControllerWalletBalancesParams.ts +25 -0
  117. package/src/index.ts +17 -0
  118. package/src/store.ts +68 -0
  119. package/src/types/assets.d.ts +29 -0
  120. package/src/types/index.ts +21 -0
  121. package/src/util/common.tsx +324 -0
  122. package/src/util/constants.tsx +213 -0
  123. package/src/util/enso-hooks.tsx +203 -0
  124. package/src/util/index.tsx +68 -0
  125. package/src/util/tx-tracker.tsx +301 -0
  126. package/src/util/wallet.tsx +258 -0
  127. package/tsconfig.json +13 -0
  128. package/vite.config.ts +51 -0
@@ -0,0 +1,404 @@
1
+ import { Box, Icon, Table, Text, Image } from "@chakra-ui/react";
2
+ import { HeaderWrapper, HeaderTitle, BodyWrapper } from "../ui/styled";
3
+ import { ChevronLeft, X } from "lucide-react";
4
+ import { useContext, useEffect, useState, useMemo, useCallback } from "react";
5
+ import { useAccount } from "wagmi";
6
+ import { Address } from "viem";
7
+ import Modal from "../modal";
8
+ import { CheckoutContext } from "../Checkout";
9
+ import { Button, IconButton } from "../ui";
10
+ import { CircleTimer } from "../CircleTimer";
11
+ import { TransactionDetailRow } from "../TransactionDetailRow";
12
+ import DepositProcessing from "../DepositProcessing";
13
+ import { useSendTxns, useRouteData, useAppDetails } from "@/util/enso-hooks";
14
+ import { getChainIcon } from "@/util";
15
+ import { getChainEtherscanUrl } from "@/util/common";
16
+ import { useTrackTx, useTxByHash } from "@/util/tx-tracker";
17
+ import QuoteParameters from "../QuoteParameters";
18
+ import { useApproveData } from "@/enso-api/api";
19
+ import { useIsApproveNeeded } from "@/util/wallet";
20
+
21
+ import SuccessIcon from "../../assets/success.svg";
22
+ import FailIcon from "../../assets/fail.svg";
23
+
24
+ type TransferStatus = "processing" | "success" | "failed" | "idle";
25
+
26
+ const useOperationsCalls = () => {
27
+ const { chainIdIn, tokenIn, amountIn } = useAppDetails();
28
+ const { address } = useAccount();
29
+
30
+ const { approveData, approveFetched } = useApproveData({
31
+ address,
32
+ token: tokenIn as Address,
33
+ chainId: chainIdIn,
34
+ amount: amountIn,
35
+ });
36
+ const { routeData, routeFetched } = useRouteData();
37
+
38
+ const { approveNeeded, allowanceFetched } = useIsApproveNeeded(
39
+ tokenIn as Address,
40
+ approveData?.tx?.to as Address,
41
+ amountIn,
42
+ );
43
+
44
+ const calls = useMemo(() => {
45
+ if (!allowanceFetched || !routeFetched || !approveFetched) return [];
46
+
47
+ if (approveNeeded) {
48
+ return [approveData?.tx, routeData?.tx];
49
+ }
50
+ return [routeData?.tx];
51
+ }, [
52
+ approveNeeded,
53
+ allowanceFetched,
54
+ routeFetched,
55
+ approveData,
56
+ routeData,
57
+ approveFetched,
58
+ ]);
59
+
60
+ return {
61
+ calls,
62
+ approveNeeded,
63
+ };
64
+ };
65
+
66
+ const WalletConfirmStep = () => {
67
+ const { handleClose, setFlow, setStep } = useContext(CheckoutContext);
68
+ const [status, setStatus] = useState<TransferStatus>("idle");
69
+ const [isTimerFinished, setIsTimerFinished] = useState(false);
70
+ const { address } = useAccount();
71
+ const [trackingHash, setTrackingHash] = useState("");
72
+ const [called, setCalled] = useState(false);
73
+
74
+ const { chainIdIn, chainIdOut } = useAppDetails();
75
+ const { calls } = useOperationsCalls();
76
+
77
+ const { sendTxns, ready } = useSendTxns({
78
+ calls,
79
+ address,
80
+ chainId: chainIdIn,
81
+ });
82
+
83
+ // const [trackingHash, setTrackingHash] = useState("");
84
+ const { track } = useTrackTx();
85
+
86
+ const isCrosschain = chainIdIn !== chainIdOut;
87
+
88
+ const onTxSend = useCallback(
89
+ (hash: string) => {
90
+ setStatus("processing");
91
+ setTrackingHash(hash);
92
+ track({
93
+ hash: hash as `0x${string}`,
94
+ isActive: true,
95
+ chainId: chainIdIn,
96
+ crosschain: isCrosschain,
97
+ status: isCrosschain
98
+ ? "(0/4) Waiting for source transaction completion"
99
+ : "Transaction in progess",
100
+ message: "Transaction confirmed",
101
+ onConfirmed: () => {
102
+ setStatus("success");
103
+ },
104
+ });
105
+ },
106
+ [chainIdIn, chainIdOut],
107
+ );
108
+
109
+ const onFail = useCallback((error: any) => {
110
+ console.error(error);
111
+ setStatus("failed");
112
+ }, []);
113
+
114
+ // Initiate the transaction when wallet is ready
115
+ useEffect(() => {
116
+ if (!called && ready) {
117
+ sendTxns(onTxSend, onFail);
118
+ setCalled(true);
119
+ }
120
+ }, [called, ready, sendTxns, onTxSend]);
121
+
122
+ const handleTimerFinish = () => {
123
+ setIsTimerFinished(true);
124
+ };
125
+
126
+ const handleNewDeposit = () => {
127
+ // Reset to initial step or handle new deposit logic
128
+ setFlow("mainFlow");
129
+ setStep("selectToken");
130
+ };
131
+
132
+ const handleRetry = () => {
133
+ // Reset to previous step to retry the transfer
134
+ // setStatus("processing");
135
+ // setIsTimerFinished(false);
136
+ setFlow("mainFlow");
137
+ setStep("quote");
138
+ };
139
+
140
+ const tx = useTxByHash(trackingHash);
141
+
142
+ const explorerUrl = isCrosschain
143
+ ? `https://layerzeroscan.com/tx/${trackingHash}`
144
+ : getChainEtherscanUrl({
145
+ hash: trackingHash,
146
+ chainId: chainIdIn,
147
+ });
148
+
149
+ // useEffect(() => {
150
+ // if (status === "processing") {
151
+ // // Simulate transfer processing - randomly succeed or fail after timer
152
+ // const timer = setTimeout(() => {
153
+ // const shouldSucceed = Math.random() > 0.3; // 70% success rate for demo
154
+ // setStatus(shouldSucceed ? "success" : "failed");
155
+ // }, 2500); // 2.5 seconds processing time
156
+
157
+ // return () => clearTimeout(timer);
158
+ // }
159
+ // }, [status]);
160
+
161
+ const getStatusColor = () => {
162
+ switch (status) {
163
+ case "success":
164
+ return "#14AE5C";
165
+ case "failed":
166
+ return "#E84142";
167
+ default:
168
+ return "#1E171F";
169
+ }
170
+ };
171
+
172
+ const getStatusText = () => {
173
+ switch (status) {
174
+ case "success":
175
+ return "Success";
176
+ case "failed":
177
+ return "Failed";
178
+ case "idle":
179
+ return "Awaiting wallet approval";
180
+ default:
181
+ return tx?.status;
182
+ }
183
+ };
184
+
185
+ const renderStatusIcon = () => {
186
+ switch (status) {
187
+ case "processing":
188
+ case "idle":
189
+ return (
190
+ <CircleTimer
191
+ start={status === "processing"}
192
+ onFinish={handleTimerFinish}
193
+ />
194
+ );
195
+
196
+ case "success":
197
+ return (
198
+ <Box
199
+ display="flex"
200
+ flexDirection="column"
201
+ alignItems="center"
202
+ >
203
+ <Image
204
+ src={SuccessIcon}
205
+ boxShadow="0px 0px 20px #14AE5C"
206
+ borderRadius="90%"
207
+ width="58px"
208
+ height="58px"
209
+ />
210
+ </Box>
211
+ );
212
+
213
+ case "failed":
214
+ return (
215
+ <Box
216
+ display="flex"
217
+ flexDirection="column"
218
+ alignItems="center"
219
+ >
220
+ <Image
221
+ src={FailIcon}
222
+ boxShadow="0px 0px 20px #E84142"
223
+ borderRadius="90%"
224
+ width="58px"
225
+ height="58px"
226
+ />
227
+ </Box>
228
+ );
229
+ }
230
+ };
231
+
232
+ const renderProcessingText = () => {
233
+ if (status === "processing" && isTimerFinished) {
234
+ return (
235
+ <Box
236
+ display="flex"
237
+ flexDirection="column"
238
+ alignItems="center"
239
+ marginTop="16px"
240
+ textAlign="center"
241
+ >
242
+ <Text
243
+ fontSize="lg"
244
+ fontWeight="semibold"
245
+ color="fg"
246
+ marginBottom="8px"
247
+ >
248
+ Deposit pending
249
+ </Text>
250
+ <Text fontSize="sm" color="fg.muted" maxWidth="280px">
251
+ Your deposit is still in progress – no action is
252
+ required from you.
253
+ </Text>
254
+ </Box>
255
+ );
256
+ }
257
+ return null;
258
+ };
259
+
260
+ return (
261
+ <>
262
+ <Modal.Header>
263
+ <HeaderWrapper>
264
+ <IconButton
265
+ minWidth={"16px"}
266
+ minHeight={"16px"}
267
+ maxWidth={"16px"}
268
+ onClick={() => {
269
+ setFlow("mainFlow");
270
+ setStep("quote");
271
+ }}
272
+ >
273
+ <Icon
274
+ as={ChevronLeft}
275
+ color="gray"
276
+ width={"16px"}
277
+ height={"16px"}
278
+ />
279
+ </IconButton>
280
+
281
+ <Box display="flex" flexDirection="column" gap={"4px"}>
282
+ <HeaderTitle>Top up your wallet</HeaderTitle>
283
+ </Box>
284
+
285
+ {handleClose && (
286
+ <IconButton
287
+ onClick={handleClose}
288
+ width={"40px"}
289
+ marginLeft={"auto"}
290
+ >
291
+ <Icon
292
+ as={X}
293
+ color="gray"
294
+ width={"16px"}
295
+ height={"16px"}
296
+ />
297
+ </IconButton>
298
+ )}
299
+ </HeaderWrapper>
300
+ </Modal.Header>
301
+ <Modal.Body>
302
+ <BodyWrapper>
303
+ <Box
304
+ display={"flex"}
305
+ flexDirection={"column"}
306
+ paddingBottom={"16px"}
307
+ alignItems={"center"}
308
+ width={"100%"}
309
+ >
310
+ {renderStatusIcon()}
311
+ {renderProcessingText()}
312
+ </Box>
313
+
314
+ <Table.Root
315
+ key={"status"}
316
+ size="sm"
317
+ variant={"outline"}
318
+ width={"100%"}
319
+ >
320
+ <Table.Body>
321
+ <Table.Row>
322
+ <Table.Cell>Status</Table.Cell>
323
+ <Table.Cell
324
+ display="flex"
325
+ textAlign="end"
326
+ justifyContent="end"
327
+ >
328
+ <Text color={getStatusColor()}>
329
+ {getStatusText()}
330
+ </Text>
331
+ </Table.Cell>
332
+ </Table.Row>
333
+ {["success", "processing"].includes(status) && (
334
+ <Table.Row>
335
+ <Table.Cell>Transaction</Table.Cell>
336
+ <Table.Cell
337
+ display="flex"
338
+ textAlign="end"
339
+ justifyContent="end"
340
+ >
341
+ {explorerUrl ? (
342
+ <a
343
+ href={explorerUrl}
344
+ target="_blank"
345
+ rel="noreferrer"
346
+ >
347
+ <Text color="blue.500">
348
+ View on{" "}
349
+ {isCrosschain
350
+ ? "LayerZero"
351
+ : "Etherscan"}
352
+ </Text>
353
+ </a>
354
+ ) : (
355
+ <Text>-</Text>
356
+ )}
357
+ </Table.Cell>
358
+ </Table.Row>
359
+ )}
360
+ </Table.Body>
361
+ </Table.Root>
362
+
363
+ <QuoteParameters />
364
+
365
+ {status === "processing" ? (
366
+ <DepositProcessing
367
+ currencyIcon={getChainIcon(chainIdOut)}
368
+ />
369
+ ) : (
370
+ <TransactionDetailRow />
371
+ )}
372
+
373
+ {status === "success" && (
374
+ <Box display="flex" gap={"12px"} width="100%">
375
+ <Button visual={"lightGray"} onClick={handleClose}>
376
+ Close
377
+ </Button>
378
+ <Button visual={"solid"} onClick={handleNewDeposit}>
379
+ New Deposit
380
+ </Button>
381
+ </Box>
382
+ )}
383
+
384
+ {status === "failed" && (
385
+ <Box display="flex" gap={"12px"} width="100%">
386
+ <Button
387
+ // variant={"surface"}
388
+ visual={"lightGray"}
389
+ onClick={handleClose}
390
+ >
391
+ Close
392
+ </Button>
393
+ <Button visual={"solid"} onClick={handleRetry}>
394
+ Retry Deposit
395
+ </Button>
396
+ </Box>
397
+ )}
398
+ </BodyWrapper>
399
+ </Modal.Body>
400
+ </>
401
+ );
402
+ };
403
+
404
+ export default WalletConfirmStep;
@@ -0,0 +1,128 @@
1
+ import { Box, Icon, Skeleton } from "@chakra-ui/react";
2
+ import {
3
+ HeaderWrapper,
4
+ HeaderTitle,
5
+ HeaderDescription,
6
+ ListWrapper,
7
+ BodyWrapper,
8
+ } from "../ui/styled";
9
+ import { ChevronLeft, X } from "lucide-react";
10
+ import { useContext, useEffect } from "react";
11
+ import Modal from "../modal";
12
+ import { CheckoutContext } from "../Checkout";
13
+ import { Button, IconButton } from "../ui";
14
+ import { AssetCard } from "../cards";
15
+ import { useAppStore } from "@/store";
16
+ import { useWalletBalance } from "@/enso-api/api";
17
+ import { formatNumber, formatUSD, normalizeValue } from "@/util";
18
+
19
+ const SelectTokenStep = () => {
20
+ const { handleClose, setFlow, setStep } = useContext(CheckoutContext);
21
+ const setIsCheckout = useAppStore((state) => state.setIsCheckout);
22
+ const setTokenIn = useAppStore((state) => state.setTokenIn);
23
+ const tokenIn = useAppStore((state) => state.tokenIn);
24
+ const setChainIdIn = useAppStore((state) => state.setChainIdIn);
25
+ const chainIdIn = useAppStore((state) => state.chainIdIn);
26
+ const { holdingsList, total, isLoading } = useWalletBalance();
27
+
28
+ useEffect(() => {
29
+ setIsCheckout(false);
30
+ }, []);
31
+
32
+ return (
33
+ <>
34
+ <Modal.Header>
35
+ <HeaderWrapper>
36
+ <IconButton
37
+ minWidth={"16px"}
38
+ minHeight={"16px"}
39
+ maxWidth={"16px"}
40
+ onClick={() => {
41
+ setFlow("");
42
+ setStep("");
43
+ }}
44
+ >
45
+ <Icon
46
+ as={ChevronLeft}
47
+ color="gray"
48
+ width={"16px"}
49
+ height={"16px"}
50
+ />
51
+ </IconButton>
52
+ <Box display="flex" flexDirection="column" gap={"4px"}>
53
+ <HeaderTitle>Deposit</HeaderTitle>
54
+ <HeaderDescription>
55
+ Balance: {formatUSD(total)}
56
+ </HeaderDescription>
57
+ </Box>
58
+ {handleClose && (
59
+ <IconButton
60
+ onClick={handleClose}
61
+ width={"40px"}
62
+ marginLeft={"auto"}
63
+ >
64
+ <Icon
65
+ as={X}
66
+ color="gray"
67
+ width={"16px"}
68
+ height={"16px"}
69
+ />
70
+ </IconButton>
71
+ )}
72
+ </HeaderWrapper>
73
+ </Modal.Header>
74
+
75
+ <Modal.Body>
76
+ <BodyWrapper>
77
+ <Box overflowY={"scroll"} maxH={"400px"}>
78
+ <ListWrapper>
79
+ {isLoading
80
+ ? Array.from({ length: 10 }).map((_, index) => (
81
+ <Skeleton
82
+ key={index}
83
+ height="40px"
84
+ width="300px"
85
+ />
86
+ ))
87
+ : holdingsList?.map((asset) => (
88
+ <AssetCard
89
+ key={`${asset.token}-${asset.chainId}`}
90
+ chainId={asset.chainId}
91
+ icon={asset.logoUri}
92
+ title={asset.name}
93
+ balance={`${formatNumber(
94
+ normalizeValue(
95
+ asset.amount,
96
+ asset.decimals,
97
+ ),
98
+ )} ${asset.symbol}`}
99
+ usdBalance={formatUSD(asset.total)}
100
+ tag={""}
101
+ loading={false}
102
+ selected={
103
+ asset.token === tokenIn &&
104
+ asset.chainId === chainIdIn
105
+ }
106
+ onClick={() => {
107
+ setTokenIn(asset.token);
108
+ setChainIdIn(asset.chainId);
109
+ }}
110
+ />
111
+ ))}
112
+ </ListWrapper>
113
+ </Box>
114
+ <Button
115
+ onClick={() => {
116
+ setStep("selectAmount");
117
+ }}
118
+ disabled={!tokenIn}
119
+ >
120
+ Continue
121
+ </Button>
122
+ </BodyWrapper>
123
+ </Modal.Body>
124
+ </>
125
+ );
126
+ };
127
+
128
+ export default SelectTokenStep;