@ensofinance/checkout-widget 0.1.6 → 0.1.8

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 (54) hide show
  1. package/dist/checkout-widget.es.js +25523 -24215
  2. package/dist/checkout-widget.es.js.map +1 -1
  3. package/dist/checkout-widget.umd.js +64 -59
  4. package/dist/checkout-widget.umd.js.map +1 -1
  5. package/dist/index.d.ts +5 -1
  6. package/package.json +1 -1
  7. package/src/assets/providers/alchemypay.svg +21 -0
  8. package/src/assets/providers/banxa.svg +21 -0
  9. package/src/assets/providers/binanceconnect.svg +14 -0
  10. package/src/assets/providers/kryptonim.svg +6 -0
  11. package/src/assets/providers/mercuryo.svg +21 -0
  12. package/src/assets/providers/moonpay.svg +14 -0
  13. package/src/assets/providers/stripe.svg +16 -0
  14. package/src/assets/providers/swapped.svg +1 -0
  15. package/src/assets/providers/topper.svg +14 -0
  16. package/src/assets/providers/transak.svg +21 -0
  17. package/src/assets/providers/unlimit.svg +21 -0
  18. package/src/components/AmountInput.tsx +41 -25
  19. package/src/components/ChakraProvider.tsx +36 -13
  20. package/src/components/Checkout.tsx +7 -1
  21. package/src/components/CurrencySwapDisplay.tsx +59 -22
  22. package/src/components/DepositProcessing.tsx +1 -1
  23. package/src/components/ExchangeConfirmSecurity.tsx +1 -1
  24. package/src/components/QuoteParameters.tsx +1 -1
  25. package/src/components/TransactionDetailRow.tsx +2 -2
  26. package/src/components/cards/ExchangeCard.tsx +1 -1
  27. package/src/components/cards/OptionCard.tsx +2 -1
  28. package/src/components/cards/WalletCard.tsx +1 -1
  29. package/src/components/modal.tsx +3 -3
  30. package/src/components/steps/CardBuyFlow/CardBuyFlow.tsx +412 -0
  31. package/src/components/steps/CardBuyFlow/ChooseAmountStep.tsx +352 -0
  32. package/src/components/steps/CardBuyFlow/OpenWidgetStep.tsx +193 -0
  33. package/src/components/steps/ExchangeFlow.tsx +254 -1416
  34. package/src/components/steps/FlowSelector.tsx +117 -60
  35. package/src/components/steps/SmartAccountFlow.tsx +372 -0
  36. package/src/components/steps/WalletFlow/WalletAmountStep.tsx +2 -2
  37. package/src/components/steps/WalletFlow/WalletConfirmStep.tsx +92 -51
  38. package/src/components/steps/WalletFlow/WalletFlow.tsx +17 -16
  39. package/src/components/steps/WalletFlow/WalletQuoteStep.tsx +2 -2
  40. package/src/components/steps/WalletFlow/WalletTokenStep.tsx +6 -4
  41. package/src/components/steps/shared/ChooseAmountStep.tsx +325 -0
  42. package/src/components/steps/shared/SignUserOpStep.tsx +117 -0
  43. package/src/components/steps/shared/TrackUserOpStep.tsx +625 -0
  44. package/src/components/steps/shared/exchangeIntegration.ts +19 -0
  45. package/src/components/steps/shared/types.ts +22 -0
  46. package/src/components/ui/index.tsx +23 -6
  47. package/src/components/ui/toaster.tsx +2 -1
  48. package/src/components/ui/transitions.tsx +16 -0
  49. package/src/types/index.ts +99 -0
  50. package/src/util/constants.tsx +27 -0
  51. package/src/util/enso-hooks.tsx +75 -61
  52. package/src/util/meld-hooks.tsx +533 -0
  53. package/src/assets/usdc.webp +0 -0
  54. package/src/assets/usdt.webp +0 -0
@@ -1,6 +1,6 @@
1
1
  import { Box, Icon, Skeleton, Text } from "@chakra-ui/react";
2
2
  import { X, AlertCircle } from "lucide-react";
3
- import { useContext, useEffect, useMemo, useState } from "react";
3
+ import { useCallback, useContext, useEffect, useMemo, useState } from "react";
4
4
  import { useAccount } from "wagmi";
5
5
  import { IconButton } from "../ui";
6
6
  import {
@@ -17,29 +17,58 @@ import { CheckoutContext } from "../Checkout";
17
17
  import { WalletCard, OptionCard } from "../cards";
18
18
  import { WalletStatus } from "../cards/WalletCard";
19
19
  import { useWalletIcon, useSmartAccountBalances } from "@/util/enso-hooks";
20
- import ExchangeFlow, {
21
- WithdrawalStep,
22
- EXCHANGE_ICON_BY_TYPE,
23
- ExchangeToIntegrationType,
24
- } from "@/components/steps/ExchangeFlow";
20
+ import ExchangeFlow from "@/components/steps/ExchangeFlow";
21
+ import CardBuyFlow, { CardBuyStep } from "@/components/steps/CardBuyFlow/CardBuyFlow";
22
+ import SmartAccountFlow from "@/components/steps/SmartAccountFlow";
25
23
  import WalletFlow, {
26
24
  WalletFlowStep,
27
25
  } from "@/components/steps/WalletFlow/WalletFlow";
26
+ import {
27
+ isMeldCardBuySupportedChain,
28
+ useCountryCode,
29
+ useMeldSupportedCrypto,
30
+ } from "@/util/meld-hooks";
31
+ import { useAppStore } from "@/store";
32
+ import mastercardIcon from "@/assets/mastercard.png";
33
+ import visaIcon from "@/assets/visa.png";
34
+ import {
35
+ ExchangeToIntegrationType,
36
+ EXCHANGE_ICON_BY_TYPE,
37
+ } from "./shared/exchangeIntegration";
38
+ // Card brand icons
39
+ const CARD_ICONS = [mastercardIcon, visaIcon];
40
+
41
+ type FlowLaunchState = {
42
+ flow: string;
43
+ presetAmount?: boolean;
44
+ } | null;
28
45
 
29
- const FLOWS = {
30
- exchange: ExchangeFlow,
31
- wallet: WalletFlow,
46
+ type FlowOption = {
47
+ id: string;
48
+ title: string;
49
+ limit: string;
50
+ delay: string;
51
+ icons: string[];
52
+ disabled?: boolean;
53
+ } & {
54
+ flow: string;
55
+ firstStep?: number;
32
56
  };
33
57
 
34
58
  const FlowSelector = () => {
35
- const { handleClose, enableExchange, enforceFlow } =
59
+ const { handleClose, enableExchange, enableCardBuy, enforceFlow } =
36
60
  useContext(CheckoutContext);
37
- const [flow, setFlow] = useState("");
38
- const [initialStep, setInitialStep] = useState<string | number>("");
61
+ const [flowLaunch, setFlowLaunch] = useState<FlowLaunchState>(null);
39
62
  const [enforceError, setEnforceError] = useState<string | null>(null);
40
63
 
41
64
  const { total, isLoading } = useWalletBalance();
42
65
  const { address } = useAccount();
66
+ const chainIdOut = useAppStore((s) => s.chainIdOut);
67
+ const { countryCode } = useCountryCode();
68
+ const { data: supportedCryptos = [] } = useMeldSupportedCrypto({
69
+ countryCode,
70
+ enabled: !!enableCardBuy && !!chainIdOut,
71
+ });
43
72
 
44
73
  const { walletIcon, walletDisplayName } = useWalletIcon();
45
74
 
@@ -47,6 +76,25 @@ const FlowSelector = () => {
47
76
  const { total: smartAccountTotal, isLoading: isLoadingSmartAccount } =
48
77
  useSmartAccountBalances(1);
49
78
 
79
+ // Check if card buy is available for this chain
80
+ const isCardBuyAvailable =
81
+ enableCardBuy &&
82
+ chainIdOut &&
83
+ isMeldCardBuySupportedChain(chainIdOut, supportedCryptos);
84
+
85
+ const handleSetFlow = useCallback((nextFlow: string) => {
86
+ if (!nextFlow) {
87
+ setFlowLaunch(null);
88
+ return;
89
+ }
90
+
91
+ setFlowLaunch({ flow: nextFlow });
92
+ }, []);
93
+
94
+ const handleCardBuyDepositDetected = useCallback(() => {
95
+ setFlowLaunch({ flow: "smart-account", presetAmount: true });
96
+ }, []);
97
+
50
98
  // Handle enforceFlow on mount
51
99
  useEffect(() => {
52
100
  if (!enforceFlow) return;
@@ -58,14 +106,15 @@ const FlowSelector = () => {
58
106
  );
59
107
  return;
60
108
  }
61
- setFlow("exchange");
62
- setInitialStep(WithdrawalStep.ChooseExchange);
109
+ setFlowLaunch({
110
+ flow: "exchange",
111
+ });
63
112
  } else if (enforceFlow === "wallet") {
64
113
  if (address) {
65
- setFlow("wallet");
66
- setInitialStep(WalletFlowStep.SelectToken);
114
+ setFlowLaunch({
115
+ flow: "wallet",
116
+ });
67
117
  }
68
- // If no address, we'll show the wallet connection prompt in the UI
69
118
  }
70
119
  }, [enforceFlow, enableExchange, address]);
71
120
 
@@ -86,37 +135,7 @@ const FlowSelector = () => {
86
135
  }, [address]);
87
136
 
88
137
  const OPTIONS = useMemo(() => {
89
- const options: {
90
- id: string;
91
- title: string;
92
- limit: string;
93
- delay: string;
94
- icons: string[];
95
- flow: string;
96
- firstStep: string | number;
97
- disabled?: boolean;
98
- }[] = [
99
- // {
100
- // id: "1",
101
- // title: "Crypto Transfer",
102
- // limit: address ? "No Limit" : "Connect wallet to proceed",
103
- // delay: address ? "Instant - 2 min" : "",
104
- // icons: [RabbyIcon, MetamaskIcon],
105
- // flow: "mainFlow",
106
- // firstStep: "selectToken",
107
- // disabled: !address,
108
- // },
109
- // {
110
- // id: "3",
111
- // title: "Deposit with card",
112
- // limit: "$10,000 limit",
113
- // delay: "5 min",
114
- // icons: [MastercardIcon, VisaIcon],
115
- // flow: "",
116
- // firstStep: "",
117
- // disabled: true,
118
- // },
119
- ];
138
+ const options: FlowOption[] = [];
120
139
 
121
140
  // Add Smart Balance option if balance > $20
122
141
  if (!isLoadingSmartAccount && smartAccountTotal > 20) {
@@ -126,12 +145,12 @@ const FlowSelector = () => {
126
145
  limit: formatUSD(smartAccountTotal),
127
146
  delay: "2 min",
128
147
  icons: [],
129
- flow: "exchange",
130
- firstStep: WithdrawalStep.ChooseBalanceAsset,
148
+ flow: "smart-account",
131
149
  });
132
150
  }
133
151
 
134
- if (Array.isArray(enableExchange) && enableExchange.length > 0)
152
+ // Add CEX exchange option
153
+ if (Array.isArray(enableExchange) && enableExchange.length > 0) {
135
154
  options.unshift({
136
155
  id: "exchange",
137
156
  title: "Connect Exchange",
@@ -146,16 +165,51 @@ const FlowSelector = () => {
146
165
  )
147
166
  .filter(Boolean),
148
167
  flow: "exchange",
149
- // Start at ChooseExchange to allow picking among multiple integrations
150
- firstStep: WithdrawalStep.ChooseExchange,
151
168
  });
169
+ }
170
+
171
+ // Add card buy option (MELD)
172
+ if (isCardBuyAvailable) {
173
+ options.push({
174
+ id: "card-buy",
175
+ title: "Buy with Card",
176
+ limit: "$10,000 limit",
177
+ delay: "1-5 min",
178
+ icons: CARD_ICONS,
179
+ flow: "card-buy",
180
+ });
181
+ }
182
+
152
183
  return options;
153
- }, [address, enableExchange, smartAccountTotal, isLoadingSmartAccount]);
184
+ }, [
185
+ enableExchange,
186
+ isCardBuyAvailable,
187
+ isLoadingSmartAccount,
188
+ smartAccountTotal,
189
+ ]);
154
190
 
155
- const FlowComponent = flow && FLOWS[flow];
191
+ switch (flowLaunch?.flow) {
192
+ case "exchange":
193
+ return <ExchangeFlow setFlow={handleSetFlow} />;
194
+
195
+ case "smart-account":
196
+ return (
197
+ <SmartAccountFlow
198
+ setFlow={handleSetFlow}
199
+ presetAmount={flowLaunch.presetAmount}
200
+ />
201
+ );
202
+
203
+ case "card-buy":
204
+ return (
205
+ <CardBuyFlow
206
+ setFlow={handleSetFlow}
207
+ onCardBuyDepositDetected={handleCardBuyDepositDetected}
208
+ />
209
+ );
156
210
 
157
- if (FlowComponent) {
158
- return <FlowComponent setFlow={setFlow} initialStep={initialStep} />;
211
+ case "wallet":
212
+ return <WalletFlow setFlow={handleSetFlow} />;
159
213
  }
160
214
 
161
215
  // Error state for enforced exchange mode with no exchanges configured
@@ -275,7 +329,9 @@ const FlowSelector = () => {
275
329
  status={WalletStatus.CONNECTED}
276
330
  badge={walletDisplayName}
277
331
  onClick={() => {
278
- setFlow("wallet");
332
+ setFlowLaunch({
333
+ flow: "wallet",
334
+ });
279
335
  }}
280
336
  />
281
337
  }
@@ -294,8 +350,9 @@ const FlowSelector = () => {
294
350
  icons={option.icons}
295
351
  onClick={() => {
296
352
  if (option.disabled) return;
297
- setFlow(option.flow);
298
- setInitialStep(option.firstStep);
353
+ setFlowLaunch({
354
+ flow: option.flow,
355
+ });
299
356
  }}
300
357
  />
301
358
  ))}
@@ -0,0 +1,372 @@
1
+ import { Center, Spinner, Box, Icon, Text, Flex } from "@chakra-ui/react";
2
+ import { ChevronLeft, X } from "lucide-react";
3
+ import { useContext, useEffect, useState } from "react";
4
+ import { useReadContract } from "wagmi";
5
+ import { erc20Abi } from "viem";
6
+
7
+ import {
8
+ BodyWrapper,
9
+ HeaderDescription,
10
+ HeaderTitle,
11
+ HeaderWrapper,
12
+ ListWrapper,
13
+ } from "../ui/styled";
14
+ import { IconButton, Button } from "../ui";
15
+ import { CheckoutContext } from "../Checkout";
16
+ import Modal from "../modal";
17
+ import { useAppStore } from "@/store";
18
+ import { AssetCard } from "../cards";
19
+ import { formatNumber, formatUSD, normalizeValue } from "@/util";
20
+ import {
21
+ useAppDetails,
22
+ useSmartAccountAddress,
23
+ useSmartAccountBalances,
24
+ } from "@/util/enso-hooks";
25
+ import ChooseAmountStep from "./shared/ChooseAmountStep";
26
+ import SignUserOpStep from "./shared/SignUserOpStep";
27
+ import TrackUserOpStep from "./shared/TrackUserOpStep";
28
+ import type { MatchedToken } from "./shared/types";
29
+ import { AnimatedStep } from "../ui/transitions";
30
+
31
+ export enum SmartAccountStep {
32
+ ChooseAsset = 0,
33
+ ChooseAmount = 1,
34
+ SignUserOp = 2,
35
+ TrackUserOp = 3,
36
+ }
37
+
38
+ const smartAccountPreviousStep: Partial<
39
+ Record<SmartAccountStep, SmartAccountStep>
40
+ > = {
41
+ [SmartAccountStep.ChooseAmount]: SmartAccountStep.ChooseAsset,
42
+ [SmartAccountStep.SignUserOp]: SmartAccountStep.ChooseAmount,
43
+ };
44
+
45
+ const ChooseDelayedBalance = ({
46
+ setStep,
47
+ onTokenSelect,
48
+ notice,
49
+ }: {
50
+ setStep: (step: SmartAccountStep) => void;
51
+ onTokenSelect: (token: MatchedToken) => void;
52
+ notice?: string | null;
53
+ }) => {
54
+ const { chainIdIn, setTokenIn, setChainIdIn } = useAppStore();
55
+ const [selectedToken, setSelectedToken] = useState<string | null>(null);
56
+
57
+ const { holdingsList, total, isLoading } = useSmartAccountBalances(1);
58
+
59
+ if (isLoading) {
60
+ return (
61
+ <Center>
62
+ <Spinner m={5} />
63
+ </Center>
64
+ );
65
+ }
66
+
67
+ return (
68
+ <BodyWrapper>
69
+ {notice ? (
70
+ <Box mb={3} width="100%" textAlign="left">
71
+ <Text fontSize="sm" color="fg.muted">
72
+ {notice}
73
+ </Text>
74
+ </Box>
75
+ ) : null}
76
+ <Box mb={4} width="100%" textAlign="left">
77
+ <HeaderDescription>
78
+ Smart Account Balance: {formatUSD(total)}
79
+ </HeaderDescription>
80
+ </Box>
81
+ <Box overflowY={"scroll"} maxH={"400px"}>
82
+ <ListWrapper>
83
+ {holdingsList?.map((asset) => (
84
+ <AssetCard
85
+ key={`${asset.token}-${asset.chainId}`}
86
+ chainId={asset.chainId}
87
+ icon={asset.logoUri}
88
+ title={asset.name}
89
+ balance={`${formatNumber(
90
+ normalizeValue(asset.amount, asset.decimals),
91
+ )} ${asset.symbol}`}
92
+ usdBalance={formatUSD(asset.total)}
93
+ tag=""
94
+ loading={false}
95
+ selected={
96
+ selectedToken === asset.token &&
97
+ chainIdIn === asset.chainId
98
+ }
99
+ onClick={() => {
100
+ setSelectedToken(asset.token);
101
+ setTokenIn(asset.token);
102
+ setChainIdIn(asset.chainId);
103
+ const mockMatchedToken: MatchedToken = {
104
+ symbol: asset.symbol,
105
+ name: asset.name,
106
+ networkId: asset.chainId.toString(),
107
+ chainId: asset.chainId,
108
+ integrationNetworks: [],
109
+ tokenAddress: asset.token,
110
+ balance: Number(
111
+ normalizeValue(
112
+ asset.amount,
113
+ asset.decimals,
114
+ ),
115
+ ),
116
+ marketValue: asset.total,
117
+ };
118
+ onTokenSelect(mockMatchedToken);
119
+ }}
120
+ />
121
+ ))}
122
+ </ListWrapper>
123
+ </Box>
124
+ {holdingsList?.length === 0 ? (
125
+ <Box textAlign="center" color="fg.subtle" py={8}>
126
+ No tokens found in smart account
127
+ </Box>
128
+ ) : null}
129
+ <Button
130
+ disabled={!selectedToken}
131
+ onClick={() => {
132
+ setStep(SmartAccountStep.ChooseAmount);
133
+ }}
134
+ >
135
+ Continue
136
+ </Button>
137
+ </BodyWrapper>
138
+ );
139
+ };
140
+
141
+ const SmartAccountFlow = ({
142
+ setFlow,
143
+ presetAmount,
144
+ }: {
145
+ setFlow: (flow: string) => void;
146
+ presetAmount?: boolean;
147
+ }) => {
148
+ const { handleClose, enforceFlow } = useContext(CheckoutContext);
149
+ const [currentStep, setCurrentStep] = useState<SmartAccountStep>(
150
+ SmartAccountStep.ChooseAsset,
151
+ );
152
+ const [selectedToken, setSelectedToken] = useState<MatchedToken | null>(
153
+ null,
154
+ );
155
+ const [userOp, setUserOp] = useState<any | null>(null);
156
+ const [launchNotice, setLaunchNotice] = useState<string | null>(null);
157
+ const [isBootstrapping, setIsBootstrapping] = useState(!!presetAmount);
158
+
159
+ const setSelectedIntegration = useAppStore(
160
+ (state) => state.setSelectedIntegration,
161
+ );
162
+
163
+ const { smartAccountAddress } = useSmartAccountAddress();
164
+
165
+ const { tokenInData, tokenInPrice, chainIdIn, tokenIn } = useAppDetails();
166
+
167
+ const { data: launchRpcBalance } = useReadContract({
168
+ chainId: chainIdIn,
169
+ address: tokenIn as `0x${string}`,
170
+ abi: erc20Abi,
171
+ functionName: "balanceOf",
172
+ args: [smartAccountAddress],
173
+ query: {
174
+ enabled: !!presetAmount && !!smartAccountAddress,
175
+ refetchInterval: isBootstrapping ? 3000 : false,
176
+ staleTime: 0,
177
+ },
178
+ });
179
+
180
+ // Set delayed integration while mounted
181
+ useEffect(() => {
182
+ setSelectedIntegration({
183
+ type: "delayed",
184
+ name: "Smart account",
185
+ id: "",
186
+ });
187
+ return () => setSelectedIntegration(null);
188
+ }, [setSelectedIntegration]);
189
+
190
+ // Card-buy bootstrap: resolve token and jump to sign step
191
+ useEffect(() => {
192
+ if (!presetAmount || !isBootstrapping) return;
193
+ if (!chainIdIn || !tokenIn || !smartAccountAddress) return;
194
+ if (typeof launchRpcBalance !== "bigint") return;
195
+ if (!tokenInData) return;
196
+
197
+ const decimals = tokenInData.decimals;
198
+ const symbol = tokenInData.symbol;
199
+ const name = tokenInData.name;
200
+
201
+ const normalizedBalance = Number(
202
+ normalizeValue(launchRpcBalance, decimals),
203
+ );
204
+ if (!Number.isFinite(normalizedBalance)) return;
205
+
206
+ const resolvedPrice = Number(tokenInPrice ?? 0);
207
+ const resolvedMarketValue =
208
+ resolvedPrice > 0 ? normalizedBalance * resolvedPrice : 0;
209
+
210
+ const synthesizedToken: MatchedToken = {
211
+ symbol,
212
+ name,
213
+ networkId: chainIdIn.toString(),
214
+ chainId: chainIdIn,
215
+ integrationNetworks: [],
216
+ tokenAddress: tokenIn,
217
+ balance: normalizedBalance,
218
+ marketValue: resolvedMarketValue,
219
+ };
220
+
221
+ setSelectedToken(synthesizedToken);
222
+ setCurrentStep(SmartAccountStep.SignUserOp);
223
+ setIsBootstrapping(false);
224
+ }, [
225
+ isBootstrapping,
226
+ presetAmount,
227
+ chainIdIn,
228
+ tokenIn,
229
+ launchRpcBalance,
230
+ tokenInData,
231
+ tokenInPrice,
232
+ smartAccountAddress,
233
+ ]);
234
+
235
+ // Timeout fallback for bootstrap
236
+ useEffect(() => {
237
+ if (!presetAmount || !isBootstrapping) return;
238
+
239
+ const timer = window.setTimeout(() => {
240
+ setIsBootstrapping(false);
241
+ setLaunchNotice(
242
+ "We could not auto-open the quote yet. Select your Smart Account USDC balance to continue.",
243
+ );
244
+ setCurrentStep(SmartAccountStep.ChooseAsset);
245
+ }, 12000);
246
+
247
+ return () => window.clearTimeout(timer);
248
+ }, [isBootstrapping, presetAmount]);
249
+
250
+ const currentStepComponent = (() => {
251
+ if (presetAmount && isBootstrapping) {
252
+ return (
253
+ <BodyWrapper>
254
+ <Flex direction="column" gap={3} align="center" py={8}>
255
+ <Spinner />
256
+ <Text color="fg.muted" fontSize="sm" textAlign="center">
257
+ Preparing your Smart Account quote...
258
+ </Text>
259
+ </Flex>
260
+ </BodyWrapper>
261
+ );
262
+ }
263
+
264
+ switch (currentStep) {
265
+ case SmartAccountStep.ChooseAsset:
266
+ return (
267
+ <ChooseDelayedBalance
268
+ setStep={setCurrentStep}
269
+ onTokenSelect={setSelectedToken}
270
+ notice={launchNotice}
271
+ />
272
+ );
273
+ case SmartAccountStep.ChooseAmount:
274
+ return (
275
+ <ChooseAmountStep
276
+ setStep={setCurrentStep}
277
+ nextStep={SmartAccountStep.SignUserOp}
278
+ selectedToken={selectedToken}
279
+ mode="smart-account"
280
+ />
281
+ );
282
+ case SmartAccountStep.SignUserOp:
283
+ return (
284
+ <SignUserOpStep
285
+ nextStep={SmartAccountStep.TrackUserOp}
286
+ setStep={setCurrentStep}
287
+ setUserOp={setUserOp}
288
+ />
289
+ );
290
+ case SmartAccountStep.TrackUserOp:
291
+ return (
292
+ <TrackUserOpStep
293
+ userOp={userOp}
294
+ onReset={() =>
295
+ setCurrentStep(SmartAccountStep.ChooseAsset)
296
+ }
297
+ />
298
+ );
299
+ default:
300
+ return null;
301
+ }
302
+ })();
303
+
304
+ return (
305
+ <>
306
+ <Modal.Header>
307
+ <HeaderWrapper>
308
+ {!(
309
+ enforceFlow &&
310
+ currentStep === SmartAccountStep.ChooseAsset
311
+ ) && (
312
+ <IconButton
313
+ minWidth={"16px"}
314
+ minHeight={"16px"}
315
+ maxWidth={"16px"}
316
+ onClick={() => {
317
+ const previousStep =
318
+ smartAccountPreviousStep[currentStep];
319
+ if (previousStep !== undefined) {
320
+ setCurrentStep(previousStep);
321
+ } else {
322
+ setFlow("");
323
+ }
324
+ }}
325
+ >
326
+ <Icon
327
+ as={ChevronLeft}
328
+ color="fg.muted"
329
+ width={"16px"}
330
+ height={"16px"}
331
+ />
332
+ </IconButton>
333
+ )}
334
+
335
+ <Box
336
+ display="flex"
337
+ flexDirection="column"
338
+ gap={"4px"}
339
+ alignItems={"center"}
340
+ width="100%"
341
+ >
342
+ <HeaderTitle>Deposit from Smart account</HeaderTitle>
343
+ </Box>
344
+
345
+ {handleClose && (
346
+ <IconButton
347
+ onClick={handleClose}
348
+ minWidth={"16px"}
349
+ minHeight={"16px"}
350
+ maxWidth={"16px"}
351
+ marginLeft={"auto"}
352
+ >
353
+ <Icon
354
+ as={X}
355
+ color="fg.muted"
356
+ width={"16px"}
357
+ height={"16px"}
358
+ />
359
+ </IconButton>
360
+ )}
361
+ </HeaderWrapper>
362
+ </Modal.Header>
363
+ <Modal.Body>
364
+ <AnimatedStep key={isBootstrapping ? "bootstrap" : currentStep}>
365
+ {currentStepComponent}
366
+ </AnimatedStep>
367
+ </Modal.Body>
368
+ </>
369
+ );
370
+ };
371
+
372
+ export default SmartAccountFlow;
@@ -10,7 +10,7 @@ import { normalizeValue, denormalizeValue } from "@/util";
10
10
  import { precisionizeNumber, getPositiveDecimalValue } from "@/util/common";
11
11
  import { useTokenBalance } from "@/util/wallet";
12
12
  import { useAppDetails } from "@/util/enso-hooks";
13
- const WalletAmountStep = ({ setStep }: { setStep: (step: string) => void }) => {
13
+ const WalletAmountStep = ({ setStep }: { setStep: (step: number) => void }) => {
14
14
  const [amountInput, setAmountInput] = useState<AmountInputValue>({
15
15
  tokenAmount: "",
16
16
  usdAmount: "10.10",
@@ -124,7 +124,7 @@ const WalletAmountStep = ({ setStep }: { setStep: (step: string) => void }) => {
124
124
  />
125
125
 
126
126
  <Button
127
- onClick={() => setStep("quote")}
127
+ onClick={() => setStep(2)}
128
128
  disabled={isAmountInvalid}
129
129
  >
130
130
  Continue