@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,169 @@
1
+ import { Box, Icon, Skeleton } from "@chakra-ui/react";
2
+ import { X } from "lucide-react";
3
+ import { useContext, useMemo } from "react";
4
+ import { useAccount } from "wagmi";
5
+ import { IconButton, Tooltip } from "../ui";
6
+ import {
7
+ HeaderWrapperSpaceBetween as InitialStepHeaderWrapper,
8
+ HeaderTitle,
9
+ ListWrapper,
10
+ BodyWrapper,
11
+ Divider,
12
+ } from "../ui/styled";
13
+ import { useWalletBalance } from "@/enso-api/api";
14
+ import { formatUSD, shortenAddress } from "@/util";
15
+ import Modal from "../modal";
16
+ import { CheckoutContext } from "../Checkout";
17
+ import { WalletCard, OptionCard } from "../cards";
18
+ import { WalletStatus } from "../cards/WalletCard";
19
+ import { useWalletIcon } from "@/util/enso-hooks";
20
+ import RabbyIcon from "../../assets/rabby.png";
21
+ import MetamaskIcon from "../../assets/metamask.png";
22
+ import MastercardIcon from "../../assets/mastercard.png";
23
+ import VisaIcon from "../../assets/visa.png";
24
+ import BinanceIcon from "../../assets/BinanceBadge.svg";
25
+
26
+ const InitialStep = () => {
27
+ const { handleClose, setStep, setFlow, enableExchanges } =
28
+ useContext(CheckoutContext);
29
+
30
+ const { total, isLoading } = useWalletBalance();
31
+ const { address, isConnected } = useAccount();
32
+
33
+ const { walletIcon, walletDisplayName } = useWalletIcon();
34
+
35
+ const formattedBalance = useMemo(() => {
36
+ if (isLoading)
37
+ return (
38
+ <Skeleton display="inline-block" height="10px" width="60px" />
39
+ );
40
+ if (typeof total === "number") {
41
+ return formatUSD(total);
42
+ }
43
+ return total || "$0.00";
44
+ }, [total, isLoading]);
45
+
46
+ const truncatedAddress = useMemo(() => {
47
+ if (!address) return "";
48
+ return shortenAddress(address);
49
+ }, [address]);
50
+
51
+ const OPTIONS = useMemo(() => {
52
+ const options: {
53
+ id: string;
54
+ title: string;
55
+ limit: string;
56
+ delay: string;
57
+ icons: string[];
58
+ flow: string;
59
+ firstStep: string;
60
+ disabled?: boolean;
61
+ }[] = [
62
+ // {
63
+ // id: "1",
64
+ // title: "Crypto Transfer",
65
+ // limit: address ? "No Limit" : "Connect wallet to proceed",
66
+ // delay: address ? "Instant - 2 min" : "",
67
+ // icons: [RabbyIcon, MetamaskIcon],
68
+ // flow: "mainFlow",
69
+ // firstStep: "selectToken",
70
+ // disabled: !address,
71
+ // },
72
+ // {
73
+ // id: "3",
74
+ // title: "Deposit with card",
75
+ // limit: "$10,000 limit",
76
+ // delay: "5 min",
77
+ // icons: [MastercardIcon, VisaIcon],
78
+ // flow: "",
79
+ // firstStep: "",
80
+ // disabled: true,
81
+ // },
82
+ ];
83
+
84
+ if (enableExchanges?.includes?.("binance"))
85
+ options.unshift({
86
+ id: "1",
87
+ title: "Connect Exchange",
88
+ limit: "No Limit",
89
+ delay: "2 min",
90
+ icons: [BinanceIcon],
91
+ flow: "exchangeFlow",
92
+ firstStep: "connectExchange",
93
+ });
94
+ return options;
95
+ }, [address, enableExchanges]);
96
+
97
+ return (
98
+ <>
99
+ <Modal.Header>
100
+ <InitialStepHeaderWrapper>
101
+ <Box display="flex" flexDirection="column" gap={"4px"}>
102
+ <HeaderTitle>Deposit</HeaderTitle>
103
+ </Box>
104
+
105
+ {handleClose && (
106
+ <IconButton onClick={handleClose} width={"40px"}>
107
+ <Icon
108
+ as={X}
109
+ color="fg.muted"
110
+ width={"16px"}
111
+ height={"16px"}
112
+ />
113
+ </IconButton>
114
+ )}
115
+ </InitialStepHeaderWrapper>
116
+ </Modal.Header>
117
+ <Modal.Body>
118
+ <BodyWrapper>
119
+ {address && (
120
+ <ListWrapper>
121
+ {
122
+ <WalletCard
123
+ key={address}
124
+ icon={walletIcon}
125
+ walletHash={truncatedAddress}
126
+ balance={formattedBalance as string}
127
+ delay="Instant"
128
+ status={WalletStatus.CONNECTED}
129
+ badge={walletDisplayName}
130
+ onClick={() => {
131
+ setFlow("mainFlow");
132
+ setStep("selectToken");
133
+ }}
134
+ />
135
+ }
136
+ </ListWrapper>
137
+ )}
138
+ {OPTIONS.length > 0 && (
139
+ <>
140
+ <Divider />
141
+ <ListWrapper>
142
+ {OPTIONS.map((option) => {
143
+ const optionCard = (
144
+ <OptionCard
145
+ key={option.id}
146
+ title={option.title}
147
+ limit={option.limit}
148
+ delay={option.delay}
149
+ icons={option.icons}
150
+ onClick={() => {
151
+ if (option.disabled) return;
152
+ setFlow(option.flow);
153
+ setStep(option.firstStep);
154
+ }}
155
+ />
156
+ );
157
+
158
+ return optionCard;
159
+ })}
160
+ </ListWrapper>
161
+ </>
162
+ )}
163
+ </BodyWrapper>
164
+ </Modal.Body>
165
+ </>
166
+ );
167
+ };
168
+
169
+ export default InitialStep;
@@ -0,0 +1,121 @@
1
+ import { useContext } from "react";
2
+ import { Box, Icon, Skeleton, Flex } from "@chakra-ui/react";
3
+ import { ChevronLeft, X } from "lucide-react";
4
+ import { useChainId, useSwitchChain } from "wagmi";
5
+ import Modal from "../modal";
6
+ import { CheckoutContext } from "../Checkout";
7
+ import { Button, IconButton, Input } from "../ui";
8
+ import { HeaderWrapper, HeaderTitle, BodyWrapper } from "../ui/styled";
9
+ import { TransactionDetailRow } from "../TransactionDetailRow";
10
+ import { useAppDetails, useRouteData } from "@/util/enso-hooks";
11
+ import { getChainName } from "@/util/common";
12
+ import QuoteParameters from "../QuoteParameters";
13
+
14
+ const QuoteStep = () => {
15
+ const { handleClose, setStep } = useContext(CheckoutContext);
16
+
17
+ const { chainIdIn } = useAppDetails();
18
+
19
+ const { routeLoading, usdAmountIn, routeData } = useRouteData();
20
+ const walletChainId = useChainId();
21
+ const { switchChain } = useSwitchChain();
22
+
23
+ const wrongChain = walletChainId !== chainIdIn;
24
+
25
+ return (
26
+ <>
27
+ <Modal.Header>
28
+ <HeaderWrapper>
29
+ <IconButton
30
+ minWidth={"16px"}
31
+ minHeight={"16px"}
32
+ maxWidth={"16px"}
33
+ onClick={() => {
34
+ setStep("selectAmount");
35
+ }}
36
+ >
37
+ <Icon
38
+ as={ChevronLeft}
39
+ color="gray"
40
+ width={"16px"}
41
+ height={"16px"}
42
+ />
43
+ </IconButton>
44
+
45
+ <Box display="flex" flexDirection="column" gap={"4px"}>
46
+ <HeaderTitle>Deposit</HeaderTitle>
47
+ </Box>
48
+
49
+ {handleClose && (
50
+ <IconButton
51
+ onClick={handleClose}
52
+ width={"40px"}
53
+ marginLeft={"auto"}
54
+ >
55
+ <Icon
56
+ as={X}
57
+ color="gray"
58
+ width={"16px"}
59
+ height={"16px"}
60
+ />
61
+ </IconButton>
62
+ )}
63
+ </HeaderWrapper>
64
+ </Modal.Header>
65
+
66
+ <Modal.Body>
67
+ <BodyWrapper>
68
+ <Flex
69
+ flexDirection={"column"}
70
+ gap={"16px"}
71
+ alignItems={"center"}
72
+ width={"100%"}
73
+ >
74
+ <Skeleton
75
+ loading={routeLoading}
76
+ width={routeLoading ? "156px" : "auto"}
77
+ >
78
+ <Input
79
+ readOnly
80
+ marginY={"8px"}
81
+ variant={"text"}
82
+ placeholder={"$10.00"}
83
+ value={usdAmountIn}
84
+ />
85
+ </Skeleton>
86
+
87
+ <QuoteParameters />
88
+ </Flex>
89
+
90
+ <TransactionDetailRow />
91
+
92
+ {wrongChain ? (
93
+ <Button
94
+ onClick={() => {
95
+ switchChain({ chainId: chainIdIn });
96
+ }}
97
+ >
98
+ Switch to {getChainName(chainIdIn)}
99
+ </Button>
100
+ ) : (
101
+ <Button
102
+ disabled={!!(routeData as any)?.error}
103
+ visual={routeLoading ? "lightGray" : "solid"}
104
+ onClick={
105
+ !routeLoading
106
+ ? () => {
107
+ setStep("confirmTransfer");
108
+ }
109
+ : () => {}
110
+ }
111
+ >
112
+ {routeLoading ? "Loading quote" : "Continue"}
113
+ </Button>
114
+ )}
115
+ </BodyWrapper>
116
+ </Modal.Body>
117
+ </>
118
+ );
119
+ };
120
+
121
+ export default QuoteStep;
@@ -0,0 +1,258 @@
1
+ import { Box, Icon, Text } from "@chakra-ui/react";
2
+ import { HeaderWrapper, HeaderTitle, BodyWrapper } from "../ui/styled";
3
+ import { ChevronLeft, X, ArrowDownUpIcon } from "lucide-react";
4
+ import { useContext, useState, useEffect, useMemo } from "react";
5
+ import { Address } from "viem";
6
+ import Modal from "../modal";
7
+ import { CheckoutContext } from "../Checkout";
8
+ import { Button, IconButton, Tab, Input } from "../ui";
9
+ import CurrencySwapDisplay from "../CurrencySwapDisplay";
10
+ import { useEnsoPrice, useEnsoToken } from "@/enso-api/api";
11
+ import { useAppStore } from "@/store";
12
+ import { normalizeValue, denormalizeValue, formatNumber } from "@/util";
13
+ import { useTokenBalance } from "@/util/wallet";
14
+
15
+ type InputMode = "usd" | "token";
16
+
17
+ const percentageOptions = [
18
+ { label: "25%", value: 25 },
19
+ { label: "50%", value: 50 },
20
+ { label: "75%", value: 75 },
21
+ { label: "Max", value: 100 },
22
+ ];
23
+
24
+ const WalletAmountStep = ({ nextStep }: { nextStep?: string }) => {
25
+ const { handleClose, setStep } = useContext(CheckoutContext);
26
+ const [usdValue, setUsdValue] = useState<string>("10.10");
27
+ // const [tokenAmount, setTokenAmount] = useState<string>("");
28
+ const [inputMode, setInputMode] = useState<InputMode>("usd");
29
+
30
+ const tokenIn = useAppStore((state) => state.tokenIn);
31
+ const tokenOut = useAppStore((state) => state.tokenOut);
32
+ const chainIdOut = useAppStore((state) => state.chainIdOut);
33
+ const chainIdIn = useAppStore((state) => state.chainIdIn);
34
+ const setAmountIn = useAppStore((state) => state.setAmountIn);
35
+ const amountIn = useAppStore((state) => state.amountIn);
36
+ const [initialLoad, setInitialLoad] = useState(true);
37
+
38
+ const {
39
+ data: [tokenDetails],
40
+ } = useEnsoToken(tokenIn, chainIdIn);
41
+ const {
42
+ data: [tokenOutDetails],
43
+ } = useEnsoToken(tokenOut, chainIdOut);
44
+ const { data: priceData } = useEnsoPrice(chainIdIn, tokenIn);
45
+
46
+ const tokenValue = useMemo(() => {
47
+ return normalizeValue(amountIn, tokenDetails?.decimals);
48
+ }, [amountIn, tokenDetails?.decimals]);
49
+
50
+ const balanceIn = useTokenBalance(tokenIn as Address, chainIdIn);
51
+
52
+ // Handle percentage selection
53
+ const handlePercentageSelect = (percent: number) => {
54
+ if (!balanceIn || !priceData || !tokenDetails?.decimals) {
55
+ setUsdValue("0.00");
56
+ return;
57
+ }
58
+
59
+ const amountToSet = (
60
+ (BigInt(balanceIn) * BigInt(percent)) /
61
+ BigInt(100)
62
+ ).toString();
63
+
64
+ setAmountIn(amountToSet);
65
+ setUsdValue(
66
+ (
67
+ +normalizeValue(amountToSet, tokenDetails?.decimals) * priceData
68
+ ).toFixed(2),
69
+ );
70
+ };
71
+
72
+ useEffect(() => {
73
+ if (initialLoad && priceData && tokenDetails && +balanceIn > 0) {
74
+ setInitialLoad(false);
75
+ handlePercentageSelect(100);
76
+ }
77
+ }, [balanceIn, initialLoad, priceData, tokenDetails, balanceIn]);
78
+
79
+ // Handle input change based on current mode
80
+ const handleInputChange = (value: string) => {
81
+ if (inputMode === "usd") {
82
+ const cleanUsd = value.replace("$", "");
83
+ // Clean the input from usd sign
84
+ setUsdValue(cleanUsd);
85
+ setAmountIn(
86
+ denormalizeValue(
87
+ (parseFloat(cleanUsd) * priceData).toString(),
88
+ tokenDetails?.decimals,
89
+ ),
90
+ );
91
+ } else {
92
+ setAmountIn(denormalizeValue(value, tokenDetails?.decimals));
93
+ setUsdValue((parseFloat(value) * priceData).toFixed(2));
94
+ }
95
+ };
96
+
97
+ // Toggle between USD and token input modes
98
+ const handleToggleMode = () => {
99
+ setInputMode(inputMode === "usd" ? "token" : "usd");
100
+ };
101
+
102
+ // Get input placeholder and display value
103
+ const getInputDisplay = () => {
104
+ if (inputMode === "usd") {
105
+ return {
106
+ placeholder: "$10.00",
107
+ displayValue: usdValue ? `$${usdValue}` : "",
108
+ equivalentValue: tokenValue
109
+ ? `${formatNumber(tokenValue)} ${tokenDetails?.symbol}`
110
+ : "—",
111
+ };
112
+ } else {
113
+ return {
114
+ placeholder: "0.00",
115
+ displayValue: tokenValue,
116
+ equivalentValue: usdValue ? `$${usdValue}` : "—",
117
+ };
118
+ }
119
+ };
120
+
121
+ const { placeholder, displayValue, equivalentValue } = getInputDisplay();
122
+ const notEnoughBalance = +balanceIn < +amountIn;
123
+
124
+ return (
125
+ <>
126
+ <Modal.Header>
127
+ <HeaderWrapper>
128
+ <IconButton
129
+ minWidth={"16px"}
130
+ minHeight={"16px"}
131
+ maxWidth={"16px"}
132
+ onClick={() => setStep("selectToken")}
133
+ >
134
+ <Icon
135
+ as={ChevronLeft}
136
+ color="gray"
137
+ width={"16px"}
138
+ height={"16px"}
139
+ />
140
+ </IconButton>
141
+
142
+ <Box display="flex" flexDirection="column" gap={"4px"}>
143
+ <HeaderTitle>Deposit</HeaderTitle>
144
+ </Box>
145
+
146
+ {handleClose && (
147
+ <IconButton
148
+ onClick={handleClose}
149
+ width={"40px"}
150
+ marginLeft={"auto"}
151
+ >
152
+ <Icon
153
+ as={X}
154
+ color="gray"
155
+ width={"16px"}
156
+ height={"16px"}
157
+ />
158
+ </IconButton>
159
+ )}
160
+ </HeaderWrapper>
161
+ </Modal.Header>
162
+
163
+ <Modal.Body>
164
+ <BodyWrapper>
165
+ <Box display={"flex"} flexDirection={"column"} gap={"8px"}>
166
+ <Box
167
+ display={"flex"}
168
+ flexDirection={"column"}
169
+ gap={"8px"}
170
+ alignItems={"center"}
171
+ padding={"25.5px"}
172
+ >
173
+ {/* Main Input */}
174
+ <Input
175
+ inputMode="decimal"
176
+ marginY={"8px"}
177
+ variant={"text"}
178
+ placeholder={placeholder}
179
+ value={displayValue}
180
+ onChange={(e) =>
181
+ handleInputChange(e.target.value)
182
+ }
183
+ />
184
+
185
+ {/* Toggle Button and Equivalent Display */}
186
+ <Box
187
+ display={"flex"}
188
+ gap={"3"}
189
+ alignItems={"center"}
190
+ onClick={handleToggleMode}
191
+ _hover={{ background: "bg.subtle" }}
192
+ cursor={"pointer"}
193
+ borderRadius={"lg"}
194
+ px={"3"}
195
+ >
196
+ <IconButton
197
+ minWidth={"24px"}
198
+ minHeight={"24px"}
199
+ maxWidth={"24px"}
200
+ background={"transparent"}
201
+ >
202
+ <Icon
203
+ as={ArrowDownUpIcon}
204
+ color="gray"
205
+ width={"16px"}
206
+ height={"16px"}
207
+ />
208
+ </IconButton>
209
+
210
+ {/* Small equivalent value display */}
211
+ <Text fontSize="sm" color="fg.muted">
212
+ {equivalentValue}
213
+ </Text>
214
+ </Box>
215
+ </Box>
216
+ <Box
217
+ display={"flex"}
218
+ gap={"4px"}
219
+ justifyContent={"center"}
220
+ paddingBottom={"35px"}
221
+ >
222
+ {percentageOptions.map((option) => (
223
+ <Tab
224
+ key={option.label}
225
+ onClick={() =>
226
+ handlePercentageSelect(option.value)
227
+ }
228
+ >
229
+ {option.label}
230
+ </Tab>
231
+ ))}
232
+ </Box>
233
+ </Box>
234
+
235
+ <CurrencySwapDisplay
236
+ tokenOut={tokenOutDetails}
237
+ tokenIn={tokenDetails}
238
+ chainIdIn={chainIdIn}
239
+ chainIdOut={chainIdOut}
240
+ />
241
+
242
+ <Button
243
+ onClick={() =>
244
+ notEnoughBalance
245
+ ? undefined
246
+ : setStep(nextStep ?? "quote")
247
+ }
248
+ disabled={notEnoughBalance}
249
+ >
250
+ Continue
251
+ </Button>
252
+ </BodyWrapper>
253
+ </Modal.Body>
254
+ </>
255
+ );
256
+ };
257
+
258
+ export default WalletAmountStep;