@ensofinance/checkout-widget 0.0.11 → 0.0.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ensofinance/checkout-widget",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "type": "module",
5
5
  "homepage": "https://www.enso.build/",
6
6
  "repository": {
@@ -1,56 +1,17 @@
1
- import {
2
- createContext,
3
- ReactElement,
4
- useEffect,
5
- useMemo,
6
- useState,
7
- ComponentType,
8
- } from "react";
1
+ import { createContext, useEffect, useMemo, ComponentType } from "react";
9
2
  import { Box } from "@chakra-ui/react";
10
- import InitialStep from "./steps/InitialStep";
11
- import SelectTokenStep from "./steps/WalletTokenStep";
12
- import SelectAmountStep from "./steps/WalletAmountStep";
13
- import QuoteStep from "./steps/QuoteStep";
14
- import WalletConfirmStep from "./steps/WalletConfirmStep";
15
- import ExchangeFlow from "./steps/ExchangeFlow";
3
+ import FlowSelector from "./steps/FlowSelector";
16
4
  import { useAppStore } from "@/store";
17
5
  import { TxTracker } from "@/util/tx-tracker";
18
6
  import ChakraProvider from "./ChakraProvider";
19
7
  import { type CheckoutConfig, type SupportedExchanges } from "@/types";
20
8
 
21
9
  type ICheckoutContext = {
22
- step: string;
23
- setStep: (step: string) => void;
24
-
25
- flow: string;
26
- setFlow: (flow: string) => void;
27
-
28
10
  handleClose: () => void;
29
11
 
30
12
  enableExchanges?: SupportedExchanges[];
31
13
  };
32
14
 
33
- const FLOWS: Record<
34
- string,
35
- {
36
- steps: Record<string, ReactElement>;
37
- }
38
- > = {
39
- mainFlow: {
40
- steps: {
41
- selectToken: <SelectTokenStep />,
42
- selectAmount: <SelectAmountStep />,
43
- quote: <QuoteStep />,
44
- confirmTransfer: <WalletConfirmStep />,
45
- },
46
- },
47
- exchangeFlow: {
48
- steps: {
49
- connectExchange: <ExchangeFlow />,
50
- },
51
- },
52
- };
53
-
54
15
  const CheckoutContext = createContext<ICheckoutContext>({} as ICheckoutContext);
55
16
 
56
17
  const Checkout = ({
@@ -62,9 +23,6 @@ const Checkout = ({
62
23
  wrapper?: ComponentType;
63
24
  onClose?: () => void;
64
25
  }) => {
65
- const [step, setStep] = useState("");
66
- const [flow, setFlow] = useState("");
67
-
68
26
  const setEnsoApiToken = useAppStore((state) => state.setEnsoApiToken);
69
27
  const setTokenOut = useAppStore((state) => state.setTokenOut);
70
28
  const setChainIdOut = useAppStore((state) => state.setChainIdOut);
@@ -76,8 +34,6 @@ const Checkout = ({
76
34
  if (onClose) {
77
35
  onClose();
78
36
  }
79
- setStep("");
80
- setFlow("");
81
37
  }
82
38
  : undefined,
83
39
  [onClose],
@@ -107,10 +63,6 @@ const Checkout = ({
107
63
  return (
108
64
  <CheckoutContext.Provider
109
65
  value={{
110
- step,
111
- setStep,
112
- flow,
113
- setFlow,
114
66
  handleClose,
115
67
  enableExchanges: enableExchange,
116
68
  }}
@@ -118,7 +70,7 @@ const Checkout = ({
118
70
  <ChakraProvider themeConfig={theme}>
119
71
  <WrapperComponent>
120
72
  <TxTracker />
121
- {!flow && !step ? <InitialStep /> : FLOWS[flow].steps[step]}
73
+ <FlowSelector />
122
74
  </WrapperComponent>
123
75
  </ChakraProvider>
124
76
  </CheckoutContext.Provider>
@@ -4,23 +4,31 @@ import {
4
4
  Flex,
5
5
  Icon,
6
6
  Image,
7
+ Link,
7
8
  Skeleton,
8
- Text,
9
9
  Table,
10
- Link,
10
+ Text,
11
11
  } from "@chakra-ui/react";
12
12
  import { ExternalLink } from "lucide-react";
13
13
  import { useAppDetails, useRouteData, useWalletIcon } from "@/util/enso-hooks";
14
- import { formatNumber, getChainIcon, normalizeValue } from "@/util";
15
- import { shortenAddress } from "@/util";
16
- import { getChainName, Token } from "@/util/common";
14
+ import {
15
+ formatNumber,
16
+ getChainIcon,
17
+ normalizeValue,
18
+ shortenAddress,
19
+ } from "@/util";
20
+ import { getChainEtherscanUrl, getChainName, Token } from "@/util/common";
17
21
  import { Tooltip } from "@/components/ui/tooltip";
18
- import { getChainEtherscanUrl } from "@/util/common";
19
- import { MOCK_IMAGE_URL, SupportedChainId } from "@/util/constants";
20
- import { STARGATE_CHAIN_NAMES } from "@/util/constants";
22
+ import {
23
+ MOCK_IMAGE_URL,
24
+ STARGATE_CHAIN_NAMES,
25
+ SupportedChainId,
26
+ } from "@/util/constants";
21
27
  import { useAppStore } from "@/store";
22
28
  // @ts-ignore
23
29
  import BinanceBadge from "../assets/BinanceBadge.svg";
30
+ import { useMemo } from "react";
31
+ import { ExchangeNames, ExchangeType } from "@/components/steps/ExchangeFlow";
24
32
 
25
33
  export const ERROR_MSG =
26
34
  "Swap not found for a required underlying of defi route, please make sure your amount is within an acceptable range";
@@ -97,7 +105,7 @@ const QuoteParameters = () => {
97
105
  useAppDetails();
98
106
  const { routeLoading, routeData, routeFetched, routerError } =
99
107
  useRouteData();
100
- const { isCheckout } = useAppStore();
108
+ const { activeExchange } = useAppStore();
101
109
  const showRouteLoading = routeLoading || (!routeFetched && !routerError);
102
110
 
103
111
  const routeErrorMessage: string | null =
@@ -117,6 +125,47 @@ const QuoteParameters = () => {
117
125
  type: "/address",
118
126
  });
119
127
 
128
+ const sourceInfo = useMemo(() => {
129
+ if (activeExchange === ExchangeType.binance)
130
+ return (
131
+ <>
132
+ <Image src={BinanceBadge} width={"16px"} height={"16px"} />
133
+ <Text>Binance</Text>
134
+ </>
135
+ );
136
+
137
+ if (activeExchange === ExchangeType.delayed)
138
+ return <Text>{ExchangeNames[ExchangeType.delayed]}</Text>;
139
+
140
+ return (
141
+ <>
142
+ {typeof walletIcon === "string" ? (
143
+ <Image src={walletIcon} width={"16px"} height={"16px"} />
144
+ ) : (
145
+ walletIcon
146
+ )}
147
+ <Tooltip content={walletDisplayName}>
148
+ <Text>
149
+ {address &&
150
+ walletDisplayName +
151
+ " " +
152
+ shortenAddress(address, true)}
153
+ </Text>
154
+ </Tooltip>
155
+ {inWalletUrl && (
156
+ <Link href={inWalletUrl} target="_blank">
157
+ <Icon
158
+ as={ExternalLink}
159
+ color="fg.muted"
160
+ width={"16px"}
161
+ height={"16px"}
162
+ />
163
+ </Link>
164
+ )}
165
+ </>
166
+ );
167
+ }, [activeExchange]);
168
+
120
169
  return (
121
170
  <>
122
171
  <Table.Root
@@ -126,7 +175,7 @@ const QuoteParameters = () => {
126
175
  width={"100%"}
127
176
  borderRadius={"sm"}
128
177
  >
129
- <Table.Body >
178
+ <Table.Body>
130
179
  <Table.Row>
131
180
  <Table.Cell>Source</Table.Cell>
132
181
  <Table.Cell
@@ -139,52 +188,7 @@ const QuoteParameters = () => {
139
188
  gap={"8px"}
140
189
  alignItems={"center"}
141
190
  >
142
- {isCheckout ? (
143
- <>
144
- <Image
145
- src={BinanceBadge}
146
- width={"16px"}
147
- height={"16px"}
148
- />
149
- <Text>Binance</Text>
150
- </>
151
- ) : (
152
- <>
153
- {typeof walletIcon === "string" ? (
154
- <Image
155
- src={walletIcon}
156
- width={"16px"}
157
- height={"16px"}
158
- />
159
- ) : (
160
- walletIcon
161
- )}
162
- <Tooltip content={walletDisplayName}>
163
- <Text>
164
- {address &&
165
- walletDisplayName +
166
- " " +
167
- shortenAddress(
168
- address,
169
- true,
170
- )}
171
- </Text>
172
- </Tooltip>
173
- {inWalletUrl && (
174
- <Link
175
- href={inWalletUrl}
176
- target="_blank"
177
- >
178
- <Icon
179
- as={ExternalLink}
180
- color="fg.muted"
181
- width={"16px"}
182
- height={"16px"}
183
- />
184
- </Link>
185
- )}
186
- </>
187
- )}
191
+ {sourceInfo}
188
192
  </Box>
189
193
  </Table.Cell>
190
194
  </Table.Row>
@@ -243,7 +247,7 @@ const QuoteParameters = () => {
243
247
  width={showRouteLoading ? "80px" : "auto"}
244
248
  >
245
249
  <Text>
246
- {isCheckout
250
+ {activeExchange === "binance"
247
251
  ? `~2min`
248
252
  : chainIdIn !== chainIdOut
249
253
  ? `~1 min`
@@ -11,8 +11,8 @@ import {
11
11
  } from "@chakra-ui/react";
12
12
  import { ChevronLeft, X, ArrowDownUpIcon } from "lucide-react";
13
13
  import { useContext, useEffect, useMemo, useState, useCallback } from "react";
14
- import { IconButton, Button, Tab, Input, Tooltip } from "../ui";
15
- import { useAccount, useSignMessage, useChainId, useSwitchChain } from "wagmi";
14
+ import { IconButton, Button, Tab, Input } from "../ui";
15
+ import { useAccount, useSignMessage } from "wagmi";
16
16
  import { getUserOperationHash } from "viem/account-abstraction";
17
17
  import {
18
18
  BodyWrapper,
@@ -36,28 +36,36 @@ import {
36
36
  formatUSD,
37
37
  normalizeValue,
38
38
  } from "@/util";
39
- import {
40
- useTokenFromListBySymbols,
41
- getChainName,
42
- precisionizeNumber,
43
- } from "@/util/common";
39
+ import { useTokenFromListBySymbols, precisionizeNumber } from "@/util/common";
44
40
  import {
45
41
  EXCHANGE_MAX_LIMIT_GAP_USD,
46
42
  EXCHANGE_MIN_LIMIT,
47
43
  } from "@/util/constants";
48
- import { useAppDetails, useRouteData } from "@/util/enso-hooks";
44
+ import {
45
+ useAppDetails,
46
+ useRouteData,
47
+ useSmartAccountBalances,
48
+ } from "@/util/enso-hooks";
49
49
  import QuoteParameters from "../QuoteParameters";
50
50
  import { TransactionDetailRow } from "../TransactionDetailRow";
51
- // @ts-ignore
52
- import SuccessIcon from "../../assets/success.svg";
53
- // @ts-ignore
54
- import FailIcon from "../../assets/fail.svg";
55
51
  import { CircleTimer } from "../CircleTimer";
56
52
  import { ConfirmExchangeStep } from "../ExchangeConfirmSecurity";
57
53
 
54
+ import SuccessIcon from "@/assets/success.svg";
55
+ import FailIcon from "@/assets/fail.svg";
56
+
58
57
  const ENTRY_POINT_ADDRESS: `0x${string}` =
59
58
  "0x0000000071727de22e5e9d8baf0edac6f37da032";
60
59
 
60
+ export enum ExchangeType {
61
+ binance = "binance",
62
+ delayed = "delayed",
63
+ }
64
+ export const ExchangeNames = {
65
+ [ExchangeType.binance]: "Binance",
66
+ [ExchangeType.delayed]: "Smart Account",
67
+ };
68
+
61
69
  // // Styled components
62
70
  // export const BodyWrapper = chakra("div", {
63
71
  // base: {
@@ -115,7 +123,7 @@ interface SupportedToken {
115
123
  interface MatchedToken extends SupportedToken {
116
124
  balance: number;
117
125
  marketValue: number;
118
- holding: CryptocurrencyPosition;
126
+ holding?: CryptocurrencyPosition;
119
127
  }
120
128
 
121
129
  // const MESH_API_URL = "http://localhost:8787";
@@ -131,22 +139,27 @@ Withdrawal steps:
131
139
  7. Open transfer modal with amount and token
132
140
  */
133
141
 
134
- enum WithdrawalStep {
142
+ export enum WithdrawalStep {
135
143
  CheckSessionKey,
136
- GetHoldings,
137
- SelectAmount,
138
- GetUserOpSignature,
144
+ ChooseExchangeAsset,
145
+ ChooseBalanceAsset,
146
+ ChooseAmount,
147
+ SignUserOp,
139
148
  InitiateWithdrawal,
140
149
  TrackUserOp,
141
150
  }
142
151
  const withdrawalSteps = [
143
152
  WithdrawalStep.CheckSessionKey,
144
- WithdrawalStep.GetHoldings,
145
- WithdrawalStep.SelectAmount,
146
- WithdrawalStep.GetUserOpSignature,
153
+ WithdrawalStep.ChooseExchangeAsset,
154
+ WithdrawalStep.ChooseAmount,
155
+ WithdrawalStep.SignUserOp,
147
156
  WithdrawalStep.InitiateWithdrawal,
148
157
  ];
149
-
158
+ const balanceSteps = [
159
+ WithdrawalStep.ChooseBalanceAsset,
160
+ WithdrawalStep.ChooseAmount,
161
+ WithdrawalStep.SignUserOp,
162
+ ];
150
163
  const BINANCE_INTEGRATION_ID = "9226e5c2-ebc3-4fdd-94f6-ed52cdce1420";
151
164
 
152
165
  // Mesh network IDs for EVM chains (from Mesh networks API)
@@ -192,13 +205,23 @@ const CheckSessionKeyStep = ({
192
205
  }: {
193
206
  setStep: (step: WithdrawalStep) => void;
194
207
  }) => {
195
- const { chainIdOut, setMeshAccessToken, setSessionId } = useAppStore();
208
+ const { chainIdOut, setMeshAccessToken, setSessionId, setChainIdIn } =
209
+ useAppStore();
196
210
  const { address } = useAccount();
197
211
  const deviceKey = useDeviceKey();
198
212
  const [showConfirmation, setShowConfirmation] = useState(false);
199
213
 
200
214
  const invalidChainId = chainIdOut && !MESH_NETWORKS.includes(chainIdOut);
201
215
  const handleMeshAccessPayload = useHandleMeshAccessPayload();
216
+ const setActiveExchange = useAppStore((state) => state.setActiveExchange);
217
+
218
+ useEffect(() => {
219
+ setActiveExchange("binance");
220
+ }, []);
221
+
222
+ useEffect(() => {
223
+ setChainIdIn(chainIdOut);
224
+ }, [chainIdOut]);
202
225
 
203
226
  useEffect(() => {
204
227
  if (invalidChainId) return;
@@ -211,7 +234,7 @@ const CheckSessionKeyStep = ({
211
234
  if (parsed?.accessToken && parsed?.sessionId) {
212
235
  setMeshAccessToken(parsed.accessToken);
213
236
  setSessionId(parsed.sessionId);
214
- setStep(WithdrawalStep.GetHoldings);
237
+ setStep(WithdrawalStep.ChooseExchangeAsset);
215
238
  return;
216
239
  }
217
240
  } catch (e) {
@@ -245,7 +268,7 @@ const CheckSessionKeyStep = ({
245
268
  onIntegrationConnected: (payload) => {
246
269
  console.log("onIntegrationConnected", payload);
247
270
  meshLink.closeLink();
248
- setStep(WithdrawalStep.GetHoldings);
271
+ setStep(WithdrawalStep.ChooseExchangeAsset);
249
272
  handleMeshAccessPayload(payload.accessToken); // Persist access token and session id for future reloads
250
273
  },
251
274
  onExit: (error) => {
@@ -500,7 +523,7 @@ const ChooseAssetStep = ({
500
523
  <Button
501
524
  disabled={!selectedTokenSymbol}
502
525
  onClick={() => {
503
- setStep(WithdrawalStep.SelectAmount);
526
+ setStep(WithdrawalStep.ChooseAmount);
504
527
  }}
505
528
  >
506
529
  Continue
@@ -510,6 +533,99 @@ const ChooseAssetStep = ({
510
533
  );
511
534
  };
512
535
 
536
+ const ChooseDelayedBalance = ({
537
+ setStep,
538
+ onTokenSelect,
539
+ }: {
540
+ setStep: (step: WithdrawalStep) => void;
541
+ onTokenSelect: (token: MatchedToken) => void;
542
+ }) => {
543
+ const { chainIdIn, setTokenIn, setChainIdIn } = useAppStore();
544
+ const [selectedToken, setSelectedToken] = useState<string | null>(null);
545
+
546
+ // Get smart account balances
547
+ const { holdingsList, total, isLoading } = useSmartAccountBalances(1);
548
+ const setActiveExchange = useAppStore((state) => state.setActiveExchange);
549
+
550
+ useEffect(() => {
551
+ setActiveExchange("delayed");
552
+ }, []);
553
+
554
+ if (isLoading) {
555
+ return (
556
+ <Center>
557
+ <Spinner m={5} />
558
+ </Center>
559
+ );
560
+ }
561
+
562
+ return (
563
+ <BodyWrapper>
564
+ <Box mb={4} width="100%" textAlign="left">
565
+ <HeaderDescription>
566
+ Smart Account Balance: {formatUSD(total)}
567
+ </HeaderDescription>
568
+ </Box>
569
+ <Box overflowY={"scroll"} maxH={"400px"}>
570
+ <ListWrapper>
571
+ {holdingsList?.map((asset) => (
572
+ <AssetCard
573
+ key={`${asset.token}-${asset.chainId}`}
574
+ chainId={asset.chainId}
575
+ icon={asset.logoUri}
576
+ title={asset.name}
577
+ balance={`${formatNumber(
578
+ normalizeValue(asset.amount, asset.decimals),
579
+ )} ${asset.symbol}`}
580
+ usdBalance={formatUSD(asset.total)}
581
+ tag=""
582
+ loading={false}
583
+ selected={
584
+ selectedToken === asset.token &&
585
+ chainIdIn === asset.chainId
586
+ }
587
+ onClick={() => {
588
+ setSelectedToken(asset.token);
589
+ setTokenIn(asset.token);
590
+ setChainIdIn(asset.chainId);
591
+ // Mock MatchedToken from balance data
592
+ const mockMatchedToken: MatchedToken = {
593
+ symbol: asset.symbol,
594
+ name: asset.name,
595
+ networkId: asset.chainId.toString(),
596
+ chainId: asset.chainId,
597
+ integrationNetworks: [],
598
+ balance: Number(
599
+ normalizeValue(
600
+ asset.amount,
601
+ asset.decimals,
602
+ ),
603
+ ),
604
+ marketValue: asset.total,
605
+ };
606
+ onTokenSelect(mockMatchedToken);
607
+ }}
608
+ />
609
+ ))}
610
+ </ListWrapper>
611
+ </Box>
612
+ {holdingsList?.length === 0 && (
613
+ <Box textAlign="center" color="fg.subtle" py={8}>
614
+ No tokens found in smart account
615
+ </Box>
616
+ )}
617
+ <Button
618
+ disabled={!selectedToken}
619
+ onClick={() => {
620
+ setStep(WithdrawalStep.ChooseAmount);
621
+ }}
622
+ >
623
+ Continue
624
+ </Button>
625
+ </BodyWrapper>
626
+ );
627
+ };
628
+
513
629
  const ChooseAmountStep = ({
514
630
  setStep,
515
631
  selectedToken,
@@ -770,7 +886,7 @@ const ChooseAmountStep = ({
770
886
  onClick={() =>
771
887
  isAmountInvalid || !amount
772
888
  ? undefined
773
- : setStep(WithdrawalStep.GetUserOpSignature)
889
+ : setStep(WithdrawalStep.SignUserOp)
774
890
  }
775
891
  disabled={isAmountInvalid || !amount}
776
892
  >
@@ -783,7 +899,9 @@ const ChooseAmountStep = ({
783
899
  const SignUserOpStep = ({
784
900
  setStep,
785
901
  setUserOp,
902
+ nextStep,
786
903
  }: {
904
+ nextStep: WithdrawalStep;
787
905
  setStep: (step: WithdrawalStep) => void;
788
906
  setUserOp: (userOp: any) => void;
789
907
  }) => {
@@ -820,8 +938,6 @@ const SignUserOpStep = ({
820
938
  chainId: chainIdIn,
821
939
  });
822
940
 
823
- console.log("Signing userOpHash:", userOpHash);
824
-
825
941
  // Sign the userOperation hash directly
826
942
  const signature = await signMessageAsync({
827
943
  account: address as `0x${string}`,
@@ -837,7 +953,7 @@ const SignUserOpStep = ({
837
953
  console.log("signedUserOp", JSON.stringify(signedUserOp));
838
954
 
839
955
  setUserOp(signedUserOp);
840
- setStep(WithdrawalStep.InitiateWithdrawal);
956
+ setStep(nextStep);
841
957
  } catch (error) {
842
958
  console.error("Failed to sign userOperation:", error);
843
959
  } finally {
@@ -982,7 +1098,7 @@ const InitiateWithdrawalStep = ({
982
1098
  onExit: (error) => {
983
1099
  console.log("Mesh link exited:", error);
984
1100
  setIsLoading(false);
985
- setStep(WithdrawalStep.GetHoldings);
1101
+ setStep(WithdrawalStep.ChooseExchangeAsset);
986
1102
  },
987
1103
  onEvent: (ev) => {
988
1104
  console.log("Mesh event:", ev);
@@ -1323,54 +1439,60 @@ const TrackUserOpStep = ({
1323
1439
  );
1324
1440
  };
1325
1441
 
1326
- const ExchangeFlow = () => {
1327
- const { handleClose, setFlow, setStep } = useContext(CheckoutContext);
1328
- const [currentStep, setCurrentStep] = useState(
1329
- WithdrawalStep.CheckSessionKey,
1330
- );
1442
+ const ExchangeFlow = ({
1443
+ setFlow,
1444
+ initialStep = WithdrawalStep.CheckSessionKey,
1445
+ }: {
1446
+ setFlow: (string) => void;
1447
+ initialStep?: WithdrawalStep;
1448
+ }) => {
1449
+ const { handleClose } = useContext(CheckoutContext);
1450
+ const [currentStep, setCurrentStep] = useState(initialStep);
1331
1451
  const [selectedToken, setSelectedToken] = useState<MatchedToken | null>(
1332
1452
  null,
1333
1453
  );
1334
1454
  const [userOp, setUserOp] = useState<any | null>(null);
1335
- const { chainIdOut } = useAppStore();
1336
- const setIsCheckout = useAppStore((state) => state.setIsCheckout);
1337
- const setChainIdIn = useAppStore((state) => state.setChainIdIn);
1338
- // const walletChainId = useChainId();
1339
- // const { switchChain } = useSwitchChain();
1340
- //
1341
- // const wrongChain = walletChainId !== chainIdOut;
1342
-
1343
- const handleTokenSelect = (token: MatchedToken) => {
1344
- setSelectedToken(token);
1345
- console.log("Selected token:", token);
1346
- };
1455
+ const setActiveExchange = useAppStore((state) => state.setActiveExchange);
1456
+ const activeExchange = useAppStore((state) => state.activeExchange);
1347
1457
 
1348
1458
  useEffect(() => {
1349
- setChainIdIn(chainIdOut);
1350
- setIsCheckout(true);
1351
- }, [chainIdOut]);
1459
+ return () => setActiveExchange("");
1460
+ }, []);
1352
1461
 
1353
1462
  const currentStepComponent = (() => {
1354
1463
  switch (currentStep) {
1355
1464
  case WithdrawalStep.CheckSessionKey:
1356
1465
  return <CheckSessionKeyStep setStep={setCurrentStep} />;
1357
- case WithdrawalStep.GetHoldings:
1466
+ case WithdrawalStep.ChooseExchangeAsset:
1358
1467
  return (
1359
1468
  <ChooseAssetStep
1360
1469
  setStep={setCurrentStep}
1361
- onTokenSelect={handleTokenSelect}
1470
+ onTokenSelect={setSelectedToken}
1362
1471
  />
1363
1472
  );
1364
- case WithdrawalStep.SelectAmount:
1473
+ case WithdrawalStep.ChooseBalanceAsset:
1474
+ return (
1475
+ <ChooseDelayedBalance
1476
+ setStep={setCurrentStep}
1477
+ onTokenSelect={setSelectedToken}
1478
+ />
1479
+ );
1480
+ case WithdrawalStep.ChooseAmount:
1365
1481
  return (
1366
1482
  <ChooseAmountStep
1367
1483
  setStep={setCurrentStep}
1368
1484
  selectedToken={selectedToken}
1369
1485
  />
1370
1486
  );
1371
- case WithdrawalStep.GetUserOpSignature:
1487
+ case WithdrawalStep.SignUserOp:
1372
1488
  return (
1373
1489
  <SignUserOpStep
1490
+ nextStep={
1491
+ // skip withdrawal if use existing balance
1492
+ selectedToken.holding
1493
+ ? WithdrawalStep.InitiateWithdrawal
1494
+ : WithdrawalStep.TrackUserOp
1495
+ }
1374
1496
  setStep={setCurrentStep}
1375
1497
  setUserOp={setUserOp}
1376
1498
  />
@@ -1413,7 +1535,6 @@ const ExchangeFlow = () => {
1413
1535
  setCurrentStep(withdrawalSteps[index]);
1414
1536
  } else {
1415
1537
  setFlow("");
1416
- setStep("");
1417
1538
  }
1418
1539
  }}
1419
1540
  >
@@ -1432,7 +1553,9 @@ const ExchangeFlow = () => {
1432
1553
  alignItems={"center"}
1433
1554
  width="100%"
1434
1555
  >
1435
- <HeaderTitle>Deposit from Binance</HeaderTitle>
1556
+ <HeaderTitle>
1557
+ Deposit from {ExchangeNames[activeExchange]}
1558
+ </HeaderTitle>
1436
1559
  </Box>
1437
1560
 
1438
1561
  {handleClose && (