@rhinestone/deposit-modal 0.2.5-alpha.0 → 0.3.0-alpha.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 (49) hide show
  1. package/README.md +40 -211
  2. package/dist/{DepositModalReown-GIODYNOK.mjs → DepositModalReown-EESTTLN4.mjs} +3 -5
  3. package/dist/{DepositModalReown-SVVA3OZ6.cjs → DepositModalReown-VV3H2WWC.cjs} +4 -6
  4. package/dist/QRCode-SMMYPUQC.cjs +58 -0
  5. package/dist/QRCode-YMQTKSSK.mjs +58 -0
  6. package/dist/{WithdrawModalReown-VNTKGALT.cjs → WithdrawModalReown-IP4MOGER.cjs} +4 -5
  7. package/dist/{WithdrawModalReown-HTEB4XGU.mjs → WithdrawModalReown-SQQQV6KQ.mjs} +3 -4
  8. package/dist/{chunk-AHQY2O3U.cjs → chunk-C6JK3IO6.cjs} +1731 -2161
  9. package/dist/{chunk-WA4RA4HB.mjs → chunk-D5YCALVX.mjs} +918 -426
  10. package/dist/{chunk-KE6CJVOV.cjs → chunk-DCAANLEP.cjs} +1110 -817
  11. package/dist/{chunk-DUGDAMAF.mjs → chunk-FY76DWPD.mjs} +1089 -796
  12. package/dist/{chunk-R2HP743T.cjs → chunk-IVTXEYB2.cjs} +65 -65
  13. package/dist/{chunk-4S262VLP.cjs → chunk-K7MNFNR7.cjs} +967 -475
  14. package/dist/{chunk-RQ2VCKLS.mjs → chunk-SLLI7SB6.mjs} +1815 -2245
  15. package/dist/{chunk-WHW3ZMOT.mjs → chunk-VA3ANS7D.mjs} +114 -114
  16. package/dist/constants.cjs +2 -2
  17. package/dist/constants.d.cts +3 -2
  18. package/dist/constants.d.ts +3 -2
  19. package/dist/constants.mjs +1 -1
  20. package/dist/deposit.cjs +4 -6
  21. package/dist/deposit.d.cts +2 -3
  22. package/dist/deposit.d.ts +2 -3
  23. package/dist/deposit.mjs +3 -5
  24. package/dist/index.cjs +5 -7
  25. package/dist/index.d.cts +5 -3
  26. package/dist/index.d.ts +5 -3
  27. package/dist/index.mjs +4 -6
  28. package/dist/styles.css +1068 -752
  29. package/dist/{types-D0NawmZ8.d.cts → types-DRou84ZM.d.cts} +147 -40
  30. package/dist/{types-CeFbJ-MW.d.ts → types-DRou84ZM.d.ts} +147 -40
  31. package/dist/withdraw.cjs +4 -5
  32. package/dist/withdraw.d.cts +2 -3
  33. package/dist/withdraw.d.ts +2 -3
  34. package/dist/withdraw.mjs +3 -4
  35. package/package.json +13 -12
  36. package/dist/chunk-J2SWZSXL.mjs +0 -295
  37. package/dist/chunk-LHOHM67Z.mjs +0 -234
  38. package/dist/chunk-YKGL66EF.cjs +0 -295
  39. package/dist/chunk-ZHLQMSQM.cjs +0 -234
  40. package/dist/reown.cjs +0 -18
  41. package/dist/reown.d.cts +0 -10
  42. package/dist/reown.d.ts +0 -10
  43. package/dist/reown.mjs +0 -18
  44. package/dist/safe-CB7TvRCc.d.cts +0 -62
  45. package/dist/safe-CB7TvRCc.d.ts +0 -62
  46. package/dist/safe.cjs +0 -22
  47. package/dist/safe.d.cts +0 -14
  48. package/dist/safe.d.ts +0 -14
  49. package/dist/safe.mjs +0 -22
@@ -1,10 +1,17 @@
1
1
  import {
2
+ AlertTriangleIcon,
3
+ BodyHeader,
2
4
  Button,
5
+ ChevronDownIcon,
6
+ ChevronLeftIcon,
7
+ CircleArrowOutUpLeftIcon,
8
+ CloseIcon,
3
9
  ConnectStep,
4
10
  Modal,
5
11
  PoweredBy,
6
12
  ProcessingStep,
7
13
  Spinner,
14
+ WalletIcon,
8
15
  accountFromPrivateKey,
9
16
  applyTheme,
10
17
  buildSessionDetails,
@@ -21,12 +28,7 @@ import {
21
28
  saveSessionOwnerToStorage,
22
29
  toEvmCaip2,
23
30
  useLatestRef
24
- } from "./chunk-DUGDAMAF.mjs";
25
- import {
26
- buildSafeTransaction,
27
- executeSafeErc20Transfer,
28
- executeSafeEthTransfer
29
- } from "./chunk-J2SWZSXL.mjs";
31
+ } from "./chunk-FY76DWPD.mjs";
30
32
  import {
31
33
  DEFAULT_BACKEND_URL,
32
34
  DEFAULT_SIGNER_ADDRESS,
@@ -39,7 +41,7 @@ import {
39
41
  getTokenDecimalsByAddress,
40
42
  getTokenIcon,
41
43
  getTokenSymbol
42
- } from "./chunk-WHW3ZMOT.mjs";
44
+ } from "./chunk-VA3ANS7D.mjs";
43
45
 
44
46
  // src/WithdrawModal.tsx
45
47
  import {
@@ -47,13 +49,128 @@ import {
47
49
  useEffect as useEffect3,
48
50
  useMemo as useMemo3,
49
51
  useRef as useRef3,
50
- useState as useState3,
52
+ useState as useState4,
51
53
  lazy,
52
54
  Suspense
53
55
  } from "react";
54
56
 
55
57
  // src/WithdrawFlow.tsx
56
- import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
58
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState3 } from "react";
59
+
60
+ // src/store/withdraw.tsx
61
+ import { createContext, createElement, useContext } from "react";
62
+ import { useStore } from "zustand";
63
+ import { createStore } from "zustand/vanilla";
64
+ function unreachable(action) {
65
+ throw new Error(
66
+ `[deposit-modal/withdraw-store] Unhandled action: ${JSON.stringify(action)}`
67
+ );
68
+ }
69
+ function applyWithdrawAction(state, action) {
70
+ switch (action.type) {
71
+ case "wallet/id-selected":
72
+ return { ...state, selectedWalletId: action.walletId };
73
+ case "registration/started":
74
+ return {
75
+ ...state,
76
+ registration: state.registration.kind === "ready" ? {
77
+ kind: "stale",
78
+ smartAccount: state.registration.smartAccount,
79
+ registeredTarget: state.registration.registeredTarget
80
+ } : { kind: "pending" }
81
+ };
82
+ case "registration/ready":
83
+ return {
84
+ ...state,
85
+ registration: {
86
+ kind: "ready",
87
+ smartAccount: action.smartAccount,
88
+ registeredTarget: action.registeredTarget
89
+ },
90
+ step: state.step === "connect" ? "form" : state.step
91
+ };
92
+ case "registration/failed":
93
+ return {
94
+ ...state,
95
+ registration: { kind: "failed", error: action.error }
96
+ };
97
+ case "form/continue":
98
+ return {
99
+ ...state,
100
+ amount: action.amount,
101
+ recipient: action.recipient,
102
+ step: "review"
103
+ };
104
+ case "review/back":
105
+ return { ...state, step: "form" };
106
+ case "withdraw/submitted":
107
+ return { ...state, txHash: action.txHash, step: "processing" };
108
+ case "withdraw/complete":
109
+ return { ...state, step: "complete" };
110
+ case "withdraw/failed":
111
+ return { ...state, step: "failed" };
112
+ case "flow/reset":
113
+ return {
114
+ ...state,
115
+ step: "form",
116
+ amount: null,
117
+ recipient: null,
118
+ txHash: null
119
+ };
120
+ case "modal/reset":
121
+ return {
122
+ ...state,
123
+ step: "connect",
124
+ selectedWalletId: null,
125
+ registration: { kind: "idle" },
126
+ amount: null,
127
+ recipient: null,
128
+ txHash: null
129
+ };
130
+ default:
131
+ return unreachable(action);
132
+ }
133
+ }
134
+ function createWithdrawStore() {
135
+ const store = createStore(() => ({
136
+ step: "connect",
137
+ selectedWalletId: null,
138
+ registration: { kind: "idle" },
139
+ amount: null,
140
+ recipient: null,
141
+ txHash: null
142
+ }));
143
+ return {
144
+ ...store,
145
+ dispatch(action) {
146
+ store.setState((state) => applyWithdrawAction(state, action));
147
+ }
148
+ };
149
+ }
150
+ var WithdrawStoreContext = createContext(null);
151
+ function WithdrawStoreProvider({
152
+ store,
153
+ children
154
+ }) {
155
+ return createElement(
156
+ WithdrawStoreContext.Provider,
157
+ { value: store },
158
+ children
159
+ );
160
+ }
161
+ function useWithdrawStoreApi() {
162
+ const store = useContext(WithdrawStoreContext);
163
+ if (!store) {
164
+ throw new Error(
165
+ "useWithdrawStore must be called inside <WithdrawStoreProvider>"
166
+ );
167
+ }
168
+ return store;
169
+ }
170
+ function useWithdrawStore(selector) {
171
+ const store = useWithdrawStoreApi();
172
+ return useStore(store, selector);
173
+ }
57
174
 
58
175
  // src/components/steps/WithdrawFormStep.tsx
59
176
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
@@ -87,6 +204,9 @@ function WithdrawFormStep({
87
204
  switchChain,
88
205
  walletIcon,
89
206
  submitting = false,
207
+ registrationPending = false,
208
+ registrationError = null,
209
+ onRecipientChange,
90
210
  onSubmit,
91
211
  onBalanceUsdChange
92
212
  }) {
@@ -196,7 +316,7 @@ function WithdrawFormStep({
196
316
  useEffect(() => {
197
317
  if (balance === null) return;
198
318
  const sym = asset.symbol.toUpperCase();
199
- if (sym !== "USDC" && sym !== "USDT") return;
319
+ if (sym !== "USDC" && sym !== "USDT" && sym !== "USDT0") return;
200
320
  try {
201
321
  const raw = formatUnits(balance, asset.decimals);
202
322
  const numeric = Number(raw);
@@ -211,7 +331,7 @@ function WithdrawFormStep({
211
331
  const parsed = Number(amount);
212
332
  if (!Number.isFinite(parsed) || parsed <= 0) return null;
213
333
  const sym = asset.symbol.toUpperCase();
214
- if (sym === "USDC" || sym === "USDT") {
334
+ if (sym === "USDC" || sym === "USDT" || sym === "USDT0") {
215
335
  return parsed;
216
336
  }
217
337
  return null;
@@ -225,8 +345,9 @@ function WithdrawFormStep({
225
345
  const handleUseConnected = useCallback(() => {
226
346
  if (!preferredConnectedRecipient) return;
227
347
  setRecipient(preferredConnectedRecipient);
348
+ onRecipientChange?.(preferredConnectedRecipient);
228
349
  setError(null);
229
- }, [preferredConnectedRecipient]);
350
+ }, [preferredConnectedRecipient, onRecipientChange]);
230
351
  const handleWithdraw = useCallback(async () => {
231
352
  if (!recipient || !/^0x[a-fA-F0-9]{40}$/.test(recipient)) {
232
353
  setError("Enter a valid recipient address");
@@ -272,6 +393,7 @@ function WithdrawFormStep({
272
393
  }
273
394
  return /* @__PURE__ */ jsxs("div", { className: "rs-step", children: [
274
395
  /* @__PURE__ */ jsxs("div", { className: "rs-step-body rs-withdraw-form", children: [
396
+ /* @__PURE__ */ jsx(BodyHeader, { icon: /* @__PURE__ */ jsx(CircleArrowOutUpLeftIcon, {}), title: "Withdraw" }),
275
397
  /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-section", children: [
276
398
  /* @__PURE__ */ jsx("label", { className: "rs-withdraw-label", children: "Recipient address" }),
277
399
  /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-input-row", children: [
@@ -283,7 +405,9 @@ function WithdrawFormStep({
283
405
  placeholder: "0x...",
284
406
  value: recipient,
285
407
  onChange: (e) => {
286
- setRecipient(e.target.value.trim());
408
+ const next = e.target.value.trim();
409
+ setRecipient(next);
410
+ onRecipientChange?.(next);
287
411
  if (error) setError(null);
288
412
  }
289
413
  }
@@ -307,24 +431,7 @@ function WithdrawFormStep({
307
431
  ),
308
432
  isRecipientConnected ? null : "Use connected"
309
433
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
310
- /* @__PURE__ */ jsx(
311
- "svg",
312
- {
313
- viewBox: "0 0 24 24",
314
- fill: "none",
315
- stroke: "currentColor",
316
- strokeWidth: "2",
317
- className: "rs-withdraw-use-connected-icon",
318
- children: /* @__PURE__ */ jsx(
319
- "path",
320
- {
321
- strokeLinecap: "round",
322
- strokeLinejoin: "round",
323
- d: "M21 12a2.25 2.25 0 00-2.25-2.25H15a3 3 0 11-6 0H5.25A2.25 2.25 0 003 12m18 0v6a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 18v-6m18 0V9M3 12V9m18 0a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 9m18 0V6a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 6v3"
324
- }
325
- )
326
- }
327
- ),
434
+ /* @__PURE__ */ jsx(WalletIcon, { className: "rs-withdraw-use-connected-icon" }),
328
435
  isRecipientConnected ? null : "Use connected"
329
436
  ] })
330
437
  }
@@ -351,19 +458,16 @@ function WithdrawFormStep({
351
458
  }
352
459
  }
353
460
  ),
354
- /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-amount-right", children: [
355
- /* @__PURE__ */ jsx("span", { className: "rs-withdraw-token-label", children: asset.symbol }),
356
- /* @__PURE__ */ jsx(
357
- "button",
358
- {
359
- type: "button",
360
- className: "rs-withdraw-max-btn",
361
- onClick: handleMaxClick,
362
- disabled: balance === null,
363
- children: "Max"
364
- }
365
- )
366
- ] })
461
+ /* @__PURE__ */ jsx("div", { className: "rs-withdraw-amount-right", children: /* @__PURE__ */ jsx(
462
+ "button",
463
+ {
464
+ type: "button",
465
+ className: "rs-withdraw-max-btn",
466
+ onClick: handleMaxClick,
467
+ disabled: balance === null,
468
+ children: "Max"
469
+ }
470
+ ) })
367
471
  ] }),
368
472
  /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-amount-info", children: [
369
473
  /* @__PURE__ */ jsx("span", { className: "rs-withdraw-usd", children: amountUsd !== null ? currencyFormatter.format(amountUsd) : "$0.00" }),
@@ -377,12 +481,12 @@ function WithdrawFormStep({
377
481
  ] }),
378
482
  /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-receive-row", children: [
379
483
  /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-receive-col", children: [
380
- /* @__PURE__ */ jsx("label", { className: "rs-withdraw-label", children: "Receive token" }),
484
+ /* @__PURE__ */ jsx("label", { className: "rs-withdraw-label rs-withdraw-label--sm", children: "Receive chain" }),
381
485
  /* @__PURE__ */ jsxs(
382
486
  "div",
383
487
  {
384
488
  className: "rs-withdraw-dropdown-container",
385
- ref: tokenDropdownRef,
489
+ ref: chainDropdownRef,
386
490
  children: [
387
491
  /* @__PURE__ */ jsxs(
388
492
  "button",
@@ -390,79 +494,67 @@ function WithdrawFormStep({
390
494
  type: "button",
391
495
  className: "rs-withdraw-dropdown",
392
496
  onClick: () => {
393
- setShowTokenDropdown(!showTokenDropdown);
394
- setShowChainDropdown(false);
497
+ setShowChainDropdown(!showChainDropdown);
498
+ setShowTokenDropdown(false);
395
499
  },
396
500
  children: [
397
501
  /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-dropdown-value", children: [
398
- getTokenIcon(targetSymbol) && /* @__PURE__ */ jsx(
502
+ getChainIcon(targetChain) && /* @__PURE__ */ jsx(
399
503
  "img",
400
504
  {
401
- src: getTokenIcon(targetSymbol),
402
- alt: targetSymbol,
505
+ src: getChainIcon(targetChain),
506
+ alt: targetChainName,
403
507
  className: "rs-withdraw-dropdown-icon"
404
508
  }
405
509
  ),
406
- /* @__PURE__ */ jsx("span", { children: targetSymbol })
510
+ /* @__PURE__ */ jsx("span", { children: targetChainName })
407
511
  ] }),
408
512
  /* @__PURE__ */ jsx(
409
- "svg",
513
+ ChevronDownIcon,
410
514
  {
411
- viewBox: "0 0 24 24",
412
- fill: "none",
413
- stroke: "currentColor",
414
- strokeWidth: "2",
415
515
  className: "rs-withdraw-dropdown-arrow",
416
516
  style: {
417
- transform: showTokenDropdown ? "rotate(180deg)" : void 0
418
- },
419
- children: /* @__PURE__ */ jsx(
420
- "path",
421
- {
422
- strokeLinecap: "round",
423
- strokeLinejoin: "round",
424
- d: "M19 9l-7 7-7-7"
425
- }
426
- )
517
+ transform: showChainDropdown ? "rotate(180deg)" : void 0
518
+ }
427
519
  }
428
520
  )
429
521
  ]
430
522
  }
431
523
  ),
432
- showTokenDropdown && /* @__PURE__ */ jsx("div", { className: "rs-withdraw-dropdown-menu", children: targetTokenOptions.map((option) => /* @__PURE__ */ jsxs(
524
+ showChainDropdown && /* @__PURE__ */ jsx("div", { className: "rs-withdraw-dropdown-menu", children: targetChains.map((chain) => /* @__PURE__ */ jsxs(
433
525
  "button",
434
526
  {
435
527
  type: "button",
436
528
  className: "rs-withdraw-dropdown-item",
437
529
  onClick: () => {
438
- onTargetTokenChange(option.address);
439
- setShowTokenDropdown(false);
530
+ onTargetChainChange(chain.id);
531
+ setShowChainDropdown(false);
440
532
  },
441
533
  children: [
442
- getTokenIcon(option.symbol) && /* @__PURE__ */ jsx(
534
+ getChainIcon(chain.id) && /* @__PURE__ */ jsx(
443
535
  "img",
444
536
  {
445
- src: getTokenIcon(option.symbol),
446
- alt: option.symbol,
537
+ src: getChainIcon(chain.id),
538
+ alt: chain.name,
447
539
  className: "rs-withdraw-dropdown-icon"
448
540
  }
449
541
  ),
450
- /* @__PURE__ */ jsx("span", { children: option.symbol })
542
+ /* @__PURE__ */ jsx("span", { children: chain.name })
451
543
  ]
452
544
  },
453
- option.address
545
+ chain.id
454
546
  )) })
455
547
  ]
456
548
  }
457
549
  )
458
550
  ] }),
459
551
  /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-receive-col", children: [
460
- /* @__PURE__ */ jsx("label", { className: "rs-withdraw-label", children: "Receive chain" }),
552
+ /* @__PURE__ */ jsx("label", { className: "rs-withdraw-label rs-withdraw-label--sm", children: "Receive token" }),
461
553
  /* @__PURE__ */ jsxs(
462
554
  "div",
463
555
  {
464
556
  className: "rs-withdraw-dropdown-container",
465
- ref: chainDropdownRef,
557
+ ref: tokenDropdownRef,
466
558
  children: [
467
559
  /* @__PURE__ */ jsxs(
468
560
  "button",
@@ -470,67 +562,55 @@ function WithdrawFormStep({
470
562
  type: "button",
471
563
  className: "rs-withdraw-dropdown",
472
564
  onClick: () => {
473
- setShowChainDropdown(!showChainDropdown);
474
- setShowTokenDropdown(false);
565
+ setShowTokenDropdown(!showTokenDropdown);
566
+ setShowChainDropdown(false);
475
567
  },
476
568
  children: [
477
569
  /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-dropdown-value", children: [
478
- getChainIcon(targetChain) && /* @__PURE__ */ jsx(
570
+ getTokenIcon(targetSymbol) && /* @__PURE__ */ jsx(
479
571
  "img",
480
572
  {
481
- src: getChainIcon(targetChain),
482
- alt: targetChainName,
573
+ src: getTokenIcon(targetSymbol),
574
+ alt: targetSymbol,
483
575
  className: "rs-withdraw-dropdown-icon"
484
576
  }
485
577
  ),
486
- /* @__PURE__ */ jsx("span", { children: targetChainName })
578
+ /* @__PURE__ */ jsx("span", { children: targetSymbol })
487
579
  ] }),
488
580
  /* @__PURE__ */ jsx(
489
- "svg",
581
+ ChevronDownIcon,
490
582
  {
491
- viewBox: "0 0 24 24",
492
- fill: "none",
493
- stroke: "currentColor",
494
- strokeWidth: "2",
495
583
  className: "rs-withdraw-dropdown-arrow",
496
584
  style: {
497
- transform: showChainDropdown ? "rotate(180deg)" : void 0
498
- },
499
- children: /* @__PURE__ */ jsx(
500
- "path",
501
- {
502
- strokeLinecap: "round",
503
- strokeLinejoin: "round",
504
- d: "M19 9l-7 7-7-7"
505
- }
506
- )
585
+ transform: showTokenDropdown ? "rotate(180deg)" : void 0
586
+ }
507
587
  }
508
588
  )
509
589
  ]
510
590
  }
511
591
  ),
512
- showChainDropdown && /* @__PURE__ */ jsx("div", { className: "rs-withdraw-dropdown-menu", children: targetChains.map((chain) => /* @__PURE__ */ jsxs(
592
+ showTokenDropdown && /* @__PURE__ */ jsx("div", { className: "rs-withdraw-dropdown-menu", children: targetTokenOptions.map((option) => /* @__PURE__ */ jsxs(
513
593
  "button",
514
594
  {
515
595
  type: "button",
516
596
  className: "rs-withdraw-dropdown-item",
517
597
  onClick: () => {
518
- onTargetChainChange(chain.id);
519
- setShowChainDropdown(false);
598
+ onTargetTokenChange(option.address);
599
+ setShowTokenDropdown(false);
520
600
  },
521
601
  children: [
522
- getChainIcon(chain.id) && /* @__PURE__ */ jsx(
602
+ getTokenIcon(option.symbol) && /* @__PURE__ */ jsx(
523
603
  "img",
524
604
  {
525
- src: getChainIcon(chain.id),
526
- alt: chain.name,
605
+ src: getTokenIcon(option.symbol),
606
+ alt: option.symbol,
527
607
  className: "rs-withdraw-dropdown-icon"
528
608
  }
529
609
  ),
530
- /* @__PURE__ */ jsx("span", { children: chain.name })
610
+ /* @__PURE__ */ jsx("span", { children: option.symbol })
531
611
  ]
532
612
  },
533
- chain.id
613
+ option.address
534
614
  )) })
535
615
  ]
536
616
  }
@@ -539,24 +619,12 @@ function WithdrawFormStep({
539
619
  ] }),
540
620
  chainMismatch && /* @__PURE__ */ jsx("div", { className: "rs-chain-switch", children: /* @__PURE__ */ jsx("div", { className: "rs-chain-switch-text", children: isSwitching ? `Switching to ${getChainName(asset.chainId)}...` : `Switch to ${getChainName(asset.chainId)} to continue.` }) }),
541
621
  error && /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-error", children: [
542
- /* @__PURE__ */ jsx(
543
- "svg",
544
- {
545
- viewBox: "0 0 24 24",
546
- fill: "none",
547
- stroke: "currentColor",
548
- strokeWidth: "2",
549
- children: /* @__PURE__ */ jsx(
550
- "path",
551
- {
552
- strokeLinecap: "round",
553
- strokeLinejoin: "round",
554
- d: "M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"
555
- }
556
- )
557
- }
558
- ),
622
+ /* @__PURE__ */ jsx(AlertTriangleIcon, {}),
559
623
  /* @__PURE__ */ jsx("span", { children: error })
624
+ ] }),
625
+ !error && registrationError && /* @__PURE__ */ jsxs("div", { className: "rs-withdraw-error", children: [
626
+ /* @__PURE__ */ jsx(AlertTriangleIcon, {}),
627
+ /* @__PURE__ */ jsx("span", { children: registrationError })
560
628
  ] })
561
629
  ] }),
562
630
  /* @__PURE__ */ jsx("div", { className: "rs-step-footer", children: /* @__PURE__ */ jsx(
@@ -565,8 +633,8 @@ function WithdrawFormStep({
565
633
  onClick: handleWithdraw,
566
634
  fullWidth: true,
567
635
  loading: isBusy,
568
- disabled: !recipient || !amount || chainMismatch || isBusy,
569
- children: isBusy ? "Preparing..." : !recipient ? "Enter Recipient Address" : !amount ? "Enter Withdraw Amount" : "Withdraw"
636
+ disabled: !recipient || !amount || chainMismatch || isBusy || Boolean(registrationError),
637
+ children: isBusy ? "Preparing..." : registrationPending ? "Preparing session..." : !recipient ? "Enter Recipient Address" : !amount ? "Enter Withdraw Amount" : "Withdraw"
570
638
  }
571
639
  ) }),
572
640
  /* @__PURE__ */ jsx(PoweredBy, {})
@@ -574,9 +642,435 @@ function WithdrawFormStep({
574
642
  }
575
643
  WithdrawFormStep.displayName = "WithdrawFormStep";
576
644
 
577
- // src/WithdrawFlow.tsx
578
- import { encodeFunctionData, erc20Abi as erc20Abi2, parseUnits as parseUnits2 } from "viem";
645
+ // src/components/steps/WithdrawReviewStep.tsx
646
+ import { useState as useState2 } from "react";
579
647
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
648
+ function shortenAddress(addr) {
649
+ return addr.length > 12 ? `${addr.slice(0, 6)}\u2026${addr.slice(-4)}` : addr;
650
+ }
651
+ function WithdrawReviewStep({
652
+ sourceChain,
653
+ sourceSymbol,
654
+ targetChain,
655
+ targetToken,
656
+ amount,
657
+ recipient,
658
+ estimatedTime = "< 1 min",
659
+ registrationPending = false,
660
+ registrationError = null,
661
+ onConfirm,
662
+ onError
663
+ }) {
664
+ const [isSubmitting, setIsSubmitting] = useState2(false);
665
+ const [error, setError] = useState2(null);
666
+ const sourceChainName = getChainName(sourceChain);
667
+ const sourceChainIcon = getChainIcon(sourceChain);
668
+ const targetSymbol = getTokenSymbol(targetToken, targetChain);
669
+ const targetChainName = getChainName(targetChain);
670
+ const targetChainIcon = getChainIcon(targetChain);
671
+ const sourceTokenIcon = getTokenIcon(sourceSymbol);
672
+ const targetTokenIcon = getTokenIcon(targetSymbol);
673
+ const handleConfirm = async () => {
674
+ setError(null);
675
+ setIsSubmitting(true);
676
+ try {
677
+ await onConfirm();
678
+ } catch (err) {
679
+ const raw = err instanceof Error ? err.message : "Withdraw failed";
680
+ const message = formatUserError(raw);
681
+ setError(message);
682
+ onError?.(message, "WITHDRAW_REVIEW_ERROR");
683
+ } finally {
684
+ setIsSubmitting(false);
685
+ }
686
+ };
687
+ const disabled = isSubmitting || registrationPending || Boolean(registrationError);
688
+ return /* @__PURE__ */ jsxs2("div", { className: "rs-screen", children: [
689
+ /* @__PURE__ */ jsxs2("div", { className: "rs-screen-body rs-screen-body--gap-32", children: [
690
+ /* @__PURE__ */ jsx2(
691
+ BodyHeader,
692
+ {
693
+ icon: /* @__PURE__ */ jsx2(CircleArrowOutUpLeftIcon, {}),
694
+ title: "Review withdrawal"
695
+ }
696
+ ),
697
+ /* @__PURE__ */ jsxs2("div", { className: "rs-amount-details", children: [
698
+ /* @__PURE__ */ jsxs2("div", { className: "rs-amount-detail-row", children: [
699
+ /* @__PURE__ */ jsx2("span", { children: "You send" }),
700
+ /* @__PURE__ */ jsxs2("span", { className: "rs-amount-detail-value", children: [
701
+ /* @__PURE__ */ jsxs2("span", { children: [
702
+ amount,
703
+ " ",
704
+ sourceSymbol
705
+ ] }),
706
+ sourceTokenIcon && /* @__PURE__ */ jsx2("span", { className: "rs-amount-detail-icon", children: /* @__PURE__ */ jsx2("img", { src: sourceTokenIcon, alt: "" }) })
707
+ ] })
708
+ ] }),
709
+ /* @__PURE__ */ jsxs2("div", { className: "rs-amount-detail-row", children: [
710
+ /* @__PURE__ */ jsx2("span", { children: "Source chain" }),
711
+ /* @__PURE__ */ jsxs2("span", { className: "rs-amount-detail-value", children: [
712
+ /* @__PURE__ */ jsx2("span", { children: sourceChainName }),
713
+ sourceChainIcon && /* @__PURE__ */ jsx2("span", { className: "rs-amount-detail-icon", children: /* @__PURE__ */ jsx2("img", { src: sourceChainIcon, alt: "" }) })
714
+ ] })
715
+ ] }),
716
+ /* @__PURE__ */ jsxs2("div", { className: "rs-amount-detail-row", children: [
717
+ /* @__PURE__ */ jsx2("span", { children: "Recipient" }),
718
+ /* @__PURE__ */ jsx2("span", { className: "rs-amount-detail-value", children: /* @__PURE__ */ jsx2("span", { children: shortenAddress(recipient) }) })
719
+ ] }),
720
+ /* @__PURE__ */ jsxs2("div", { className: "rs-amount-detail-row", children: [
721
+ /* @__PURE__ */ jsx2("span", { children: "Receive" }),
722
+ /* @__PURE__ */ jsxs2("span", { className: "rs-amount-detail-value", children: [
723
+ /* @__PURE__ */ jsxs2("span", { children: [
724
+ amount,
725
+ " ",
726
+ targetSymbol
727
+ ] }),
728
+ targetTokenIcon && /* @__PURE__ */ jsx2("span", { className: "rs-amount-detail-icon", children: /* @__PURE__ */ jsx2("img", { src: targetTokenIcon, alt: "" }) })
729
+ ] })
730
+ ] }),
731
+ /* @__PURE__ */ jsxs2("div", { className: "rs-amount-detail-row", children: [
732
+ /* @__PURE__ */ jsx2("span", { children: "Destination chain" }),
733
+ /* @__PURE__ */ jsxs2("span", { className: "rs-amount-detail-value", children: [
734
+ /* @__PURE__ */ jsx2("span", { children: targetChainName }),
735
+ targetChainIcon && /* @__PURE__ */ jsx2("span", { className: "rs-amount-detail-icon", children: /* @__PURE__ */ jsx2("img", { src: targetChainIcon, alt: "" }) })
736
+ ] })
737
+ ] }),
738
+ /* @__PURE__ */ jsxs2("div", { className: "rs-amount-detail-row", children: [
739
+ /* @__PURE__ */ jsx2("span", { children: "Estimated time" }),
740
+ /* @__PURE__ */ jsx2("span", { className: "rs-amount-detail-value", children: estimatedTime })
741
+ ] })
742
+ ] }),
743
+ error && /* @__PURE__ */ jsxs2("div", { className: "rs-amount-error", role: "alert", children: [
744
+ /* @__PURE__ */ jsx2(AlertTriangleIcon, { style: { width: 16, height: 16, flexShrink: 0 } }),
745
+ /* @__PURE__ */ jsx2("span", { children: error })
746
+ ] }),
747
+ !error && registrationError && /* @__PURE__ */ jsxs2("div", { className: "rs-amount-error", role: "alert", children: [
748
+ /* @__PURE__ */ jsx2(AlertTriangleIcon, { style: { width: 16, height: 16, flexShrink: 0 } }),
749
+ /* @__PURE__ */ jsx2("span", { children: registrationError })
750
+ ] }),
751
+ /* @__PURE__ */ jsx2(
752
+ Button,
753
+ {
754
+ onClick: handleConfirm,
755
+ loading: isSubmitting,
756
+ loadingText: "Submitting transaction...",
757
+ disabled,
758
+ fullWidth: true,
759
+ children: "Continue"
760
+ }
761
+ )
762
+ ] }),
763
+ /* @__PURE__ */ jsx2(PoweredBy, {})
764
+ ] });
765
+ }
766
+ WithdrawReviewStep.displayName = "WithdrawReviewStep";
767
+
768
+ // src/core/safe.ts
769
+ import {
770
+ concat,
771
+ encodeFunctionData,
772
+ erc20Abi as erc20Abi2,
773
+ hashTypedData,
774
+ pad,
775
+ parseEventLogs,
776
+ toHex,
777
+ zeroAddress
778
+ } from "viem";
779
+ var SAFE_ABI = [
780
+ {
781
+ type: "function",
782
+ name: "isOwner",
783
+ stateMutability: "view",
784
+ inputs: [{ name: "owner", type: "address" }],
785
+ outputs: [{ name: "", type: "bool" }]
786
+ },
787
+ {
788
+ type: "function",
789
+ name: "nonce",
790
+ stateMutability: "view",
791
+ inputs: [],
792
+ outputs: [{ type: "uint256" }]
793
+ },
794
+ {
795
+ type: "function",
796
+ name: "execTransaction",
797
+ stateMutability: "payable",
798
+ inputs: [
799
+ { name: "to", type: "address" },
800
+ { name: "value", type: "uint256" },
801
+ { name: "data", type: "bytes" },
802
+ { name: "operation", type: "uint8" },
803
+ { name: "safeTxGas", type: "uint256" },
804
+ { name: "baseGas", type: "uint256" },
805
+ { name: "gasPrice", type: "uint256" },
806
+ { name: "gasToken", type: "address" },
807
+ { name: "refundReceiver", type: "address" },
808
+ { name: "signatures", type: "bytes" }
809
+ ],
810
+ outputs: [{ name: "success", type: "bool" }]
811
+ },
812
+ {
813
+ type: "event",
814
+ name: "ExecutionSuccess",
815
+ inputs: [
816
+ { name: "txHash", type: "bytes32", indexed: true },
817
+ { name: "payment", type: "uint256", indexed: false }
818
+ ],
819
+ anonymous: false
820
+ },
821
+ {
822
+ type: "event",
823
+ name: "ExecutionFailure",
824
+ inputs: [
825
+ { name: "txHash", type: "bytes32", indexed: true },
826
+ { name: "payment", type: "uint256", indexed: false }
827
+ ],
828
+ anonymous: false
829
+ }
830
+ ];
831
+ async function executeSafeEthTransfer(params) {
832
+ const {
833
+ walletClient,
834
+ publicClient,
835
+ safeAddress,
836
+ recipient,
837
+ amount,
838
+ chainId
839
+ } = params;
840
+ const account = walletClient.account;
841
+ const chain = walletClient.chain;
842
+ if (!account || !chain) {
843
+ throw new Error("Wallet not connected");
844
+ }
845
+ if (chain.id !== chainId) {
846
+ throw new Error(`Switch to ${getChainName(chainId)} to sign`);
847
+ }
848
+ const isOwner = await publicClient.readContract({
849
+ address: safeAddress,
850
+ abi: SAFE_ABI,
851
+ functionName: "isOwner",
852
+ args: [account.address]
853
+ });
854
+ if (!isOwner) {
855
+ throw new Error("Connected wallet is not a Safe owner");
856
+ }
857
+ const safeTx = {
858
+ to: recipient,
859
+ value: amount,
860
+ data: "0x",
861
+ operation: 0,
862
+ safeTxGas: 0n,
863
+ baseGas: 0n,
864
+ gasPrice: 0n,
865
+ gasToken: zeroAddress,
866
+ refundReceiver: zeroAddress
867
+ };
868
+ const signature = concat([
869
+ pad(account.address, { size: 32 }),
870
+ pad(toHex(0), { size: 32 }),
871
+ toHex(1, { size: 1 })
872
+ ]);
873
+ const txHash = await walletClient.writeContract({
874
+ account,
875
+ chain,
876
+ address: safeAddress,
877
+ abi: SAFE_ABI,
878
+ functionName: "execTransaction",
879
+ args: [
880
+ safeTx.to,
881
+ safeTx.value,
882
+ safeTx.data,
883
+ safeTx.operation,
884
+ safeTx.safeTxGas,
885
+ safeTx.baseGas,
886
+ safeTx.gasPrice,
887
+ safeTx.gasToken,
888
+ safeTx.refundReceiver,
889
+ signature
890
+ ]
891
+ });
892
+ const receipt = await publicClient.waitForTransactionReceipt({
893
+ hash: txHash
894
+ });
895
+ const safeLogs = receipt.logs.filter(
896
+ (log) => log.address.toLowerCase() === safeAddress.toLowerCase()
897
+ );
898
+ const parsed = parseEventLogs({
899
+ abi: SAFE_ABI,
900
+ logs: safeLogs,
901
+ strict: false
902
+ });
903
+ const failed = parsed.find((log) => log.eventName === "ExecutionFailure");
904
+ if (failed) {
905
+ throw new Error("Safe transaction failed");
906
+ }
907
+ const succeeded = parsed.find((log) => log.eventName === "ExecutionSuccess");
908
+ if (!succeeded) {
909
+ throw new Error("Safe transaction status unavailable");
910
+ }
911
+ return { txHash };
912
+ }
913
+ async function executeSafeErc20Transfer(params) {
914
+ const {
915
+ walletClient,
916
+ publicClient,
917
+ safeAddress,
918
+ tokenAddress,
919
+ recipient,
920
+ amount,
921
+ chainId
922
+ } = params;
923
+ const account = walletClient.account;
924
+ const chain = walletClient.chain;
925
+ if (!account || !chain) {
926
+ throw new Error("Wallet not connected");
927
+ }
928
+ if (chain.id !== chainId) {
929
+ throw new Error(`Switch to ${getChainName(chainId)} to sign`);
930
+ }
931
+ const isOwner = await publicClient.readContract({
932
+ address: safeAddress,
933
+ abi: SAFE_ABI,
934
+ functionName: "isOwner",
935
+ args: [account.address]
936
+ });
937
+ if (!isOwner) {
938
+ throw new Error("Connected wallet is not a Safe owner");
939
+ }
940
+ const data = encodeFunctionData({
941
+ abi: erc20Abi2,
942
+ functionName: "transfer",
943
+ args: [recipient, amount]
944
+ });
945
+ const safeTx = {
946
+ to: tokenAddress,
947
+ value: 0n,
948
+ data,
949
+ operation: 0,
950
+ safeTxGas: 0n,
951
+ baseGas: 0n,
952
+ gasPrice: 0n,
953
+ gasToken: zeroAddress,
954
+ refundReceiver: zeroAddress
955
+ };
956
+ const signature = concat([
957
+ pad(account.address, { size: 32 }),
958
+ pad(toHex(0), { size: 32 }),
959
+ toHex(1, { size: 1 })
960
+ ]);
961
+ const txHash = await walletClient.writeContract({
962
+ account,
963
+ chain,
964
+ address: safeAddress,
965
+ abi: SAFE_ABI,
966
+ functionName: "execTransaction",
967
+ args: [
968
+ safeTx.to,
969
+ safeTx.value,
970
+ safeTx.data,
971
+ safeTx.operation,
972
+ safeTx.safeTxGas,
973
+ safeTx.baseGas,
974
+ safeTx.gasPrice,
975
+ safeTx.gasToken,
976
+ safeTx.refundReceiver,
977
+ signature
978
+ ]
979
+ });
980
+ const receipt = await publicClient.waitForTransactionReceipt({
981
+ hash: txHash
982
+ });
983
+ const safeLogs = receipt.logs.filter(
984
+ (log) => log.address.toLowerCase() === safeAddress.toLowerCase()
985
+ );
986
+ const parsed = parseEventLogs({
987
+ abi: SAFE_ABI,
988
+ logs: safeLogs,
989
+ strict: false
990
+ });
991
+ const failed = parsed.find((log) => log.eventName === "ExecutionFailure");
992
+ if (failed) {
993
+ throw new Error("Safe transaction failed");
994
+ }
995
+ const succeeded = parsed.find((log) => log.eventName === "ExecutionSuccess");
996
+ if (!succeeded) {
997
+ throw new Error("Safe transaction status unavailable");
998
+ }
999
+ return { txHash };
1000
+ }
1001
+ var SAFE_TX_TYPES = {
1002
+ SafeTx: [
1003
+ { name: "to", type: "address" },
1004
+ { name: "value", type: "uint256" },
1005
+ { name: "data", type: "bytes" },
1006
+ { name: "operation", type: "uint8" },
1007
+ { name: "safeTxGas", type: "uint256" },
1008
+ { name: "baseGas", type: "uint256" },
1009
+ { name: "gasPrice", type: "uint256" },
1010
+ { name: "gasToken", type: "address" },
1011
+ { name: "refundReceiver", type: "address" },
1012
+ { name: "nonce", type: "uint256" }
1013
+ ]
1014
+ };
1015
+ async function buildSafeTransaction(params) {
1016
+ const { publicClient, safeAddress, to, value, data, chainId } = params;
1017
+ const nonce = await publicClient.readContract({
1018
+ address: safeAddress,
1019
+ abi: SAFE_ABI,
1020
+ functionName: "nonce"
1021
+ });
1022
+ const message = {
1023
+ to,
1024
+ value,
1025
+ data,
1026
+ operation: 0,
1027
+ safeTxGas: 0n,
1028
+ baseGas: 0n,
1029
+ gasPrice: 0n,
1030
+ gasToken: zeroAddress,
1031
+ refundReceiver: zeroAddress,
1032
+ nonce
1033
+ };
1034
+ const safeTxHash = hashTypedData({
1035
+ domain: { chainId, verifyingContract: safeAddress },
1036
+ types: SAFE_TX_TYPES,
1037
+ primaryType: "SafeTx",
1038
+ message
1039
+ });
1040
+ return {
1041
+ chainId,
1042
+ safeAddress,
1043
+ safeTxHash,
1044
+ typedData: {
1045
+ domain: { chainId, verifyingContract: safeAddress },
1046
+ types: SAFE_TX_TYPES,
1047
+ primaryType: "SafeTx",
1048
+ message
1049
+ }
1050
+ };
1051
+ }
1052
+
1053
+ // src/WithdrawFlow.tsx
1054
+ import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi3, parseUnits as parseUnits2 } from "viem";
1055
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1056
+ var ADDR_REGEX = /^0x[a-fA-F0-9]{40}$/;
1057
+ var REGISTRATION_DEBOUNCE_MS = 600;
1058
+ function resolveSessionOwner(eoaAddress) {
1059
+ const localOwner = loadSessionOwnerFromStorage(eoaAddress);
1060
+ if (localOwner) {
1061
+ return {
1062
+ account: accountFromPrivateKey(localOwner.privateKey),
1063
+ address: localOwner.address
1064
+ };
1065
+ }
1066
+ const created = createSessionOwnerKey();
1067
+ saveSessionOwnerToStorage(eoaAddress, created.privateKey, created.address);
1068
+ return { account: created.account, address: created.address };
1069
+ }
1070
+ function targetsEqual(a, b) {
1071
+ if (!a) return false;
1072
+ return a.chain === b.chain && a.token.toLowerCase() === b.token.toLowerCase() && (a.recipient?.toLowerCase() ?? "") === (b.recipient?.toLowerCase() ?? "");
1073
+ }
580
1074
  function WithdrawFlow({
581
1075
  dappWalletClient,
582
1076
  dappPublicClient,
@@ -599,30 +1093,17 @@ function WithdrawFlow({
599
1093
  onDisconnect,
600
1094
  onSignTransaction,
601
1095
  onRequestConnect,
602
- connectButtonLabel,
603
1096
  onStepChange,
604
- onTotalBalanceChange,
605
1097
  onClose,
606
- onConnected,
607
- onWithdrawSubmitted,
608
- onWithdrawComplete,
609
- onWithdrawFailed,
1098
+ onLifecycle,
610
1099
  onEvent,
611
1100
  onError,
612
1101
  debug
613
1102
  }) {
614
1103
  const onStepChangeRef = useLatestRef(onStepChange);
615
- const onTotalBalanceChangeRef = useLatestRef(onTotalBalanceChange);
616
1104
  const onEventRef = useLatestRef(onEvent);
617
- const onConnectedRef = useLatestRef(onConnected);
618
- const onWithdrawSubmittedRef = useLatestRef(onWithdrawSubmitted);
619
- const onWithdrawCompleteRef = useLatestRef(onWithdrawComplete);
620
- const onWithdrawFailedRef = useLatestRef(onWithdrawFailed);
1105
+ const onLifecycleRef = useLatestRef(onLifecycle);
621
1106
  const onErrorRef = useLatestRef(onError);
622
- const [step, setStep] = useState2({ type: "form" });
623
- const [isSubmitting, setIsSubmitting] = useState2(false);
624
- const [totalBalanceUsd, setTotalBalanceUsd] = useState2(0);
625
- const [isConnectSelectionConfirmed, setIsConnectSelectionConfirmed] = useState2(false);
626
1107
  const logFlow = useCallback2(
627
1108
  (message, data) => {
628
1109
  debugLog(debug, "withdraw-flow", message, data);
@@ -635,12 +1116,20 @@ function WithdrawFlow({
635
1116
  },
636
1117
  [debug]
637
1118
  );
638
- const [targetChain, setTargetChain] = useState2(targetChainProp);
639
- const [targetToken, setTargetToken] = useState2(targetTokenProp);
1119
+ const [targetChain, setTargetChain] = useState3(targetChainProp);
1120
+ const [targetToken, setTargetToken] = useState3(targetTokenProp);
1121
+ const [recipientInput, setRecipientInput] = useState3(
1122
+ defaultRecipient ?? ""
1123
+ );
1124
+ const [totalBalanceUsd, setTotalBalanceUsd] = useState3(0);
1125
+ const [isConnectSelectionConfirmed, setIsConnectSelectionConfirmed] = useState3(false);
640
1126
  useEffect2(() => {
641
1127
  setTargetChain(targetChainProp);
642
1128
  setTargetToken(targetTokenProp);
643
1129
  }, [targetChainProp, targetTokenProp]);
1130
+ useEffect2(() => {
1131
+ if (defaultRecipient) setRecipientInput(defaultRecipient);
1132
+ }, [defaultRecipient]);
644
1133
  const hasCustomSigner = Boolean(dappAddress && onSignTransaction);
645
1134
  const dappSwitchChain = useMemo2(() => {
646
1135
  if (!dappWalletClient?.switchChain) return void 0;
@@ -661,7 +1150,7 @@ function WithdrawFlow({
661
1150
  });
662
1151
  seen.add(id);
663
1152
  }
664
- if (reownWallet?.address && reownWallet.isConnected && reownWallet.walletClient && reownWallet.publicClient && !seen.has(reownWallet.address.toLowerCase())) {
1153
+ if (reownWallet?.address && reownWallet.isConnected && reownWallet.walletClient && reownWallet.publicClient) {
665
1154
  const id = `evm:${reownWallet.address.toLowerCase()}`;
666
1155
  if (!seen.has(id)) {
667
1156
  options.push({
@@ -680,10 +1169,18 @@ function WithdrawFlow({
680
1169
  reownWallet?.address,
681
1170
  reownWallet?.isConnected,
682
1171
  reownWallet?.walletClient,
683
- reownWallet?.publicClient
1172
+ reownWallet?.publicClient,
1173
+ reownWallet?.icon
684
1174
  ]);
685
1175
  const canAutoLock = hasCustomSigner || Boolean(dappWalletClient?.account && dappAddress) && !reownWallet;
686
- const [selectedWalletId, setSelectedWalletId] = useState2(null);
1176
+ const storeApi = useWithdrawStoreApi();
1177
+ const selectedWalletId = useWithdrawStore((s) => s.selectedWalletId);
1178
+ const registration = useWithdrawStore((s) => s.registration);
1179
+ const flowStep = useWithdrawStore((s) => s.step);
1180
+ const setSelectedWalletId = useCallback2(
1181
+ (walletId) => storeApi.dispatch({ type: "wallet/id-selected", walletId }),
1182
+ [storeApi]
1183
+ );
687
1184
  const signerContext = useMemo2(() => {
688
1185
  if (canAutoLock) {
689
1186
  if (hasCustomSigner) {
@@ -702,7 +1199,7 @@ function WithdrawFlow({
702
1199
  };
703
1200
  }
704
1201
  if (!isConnectSelectionConfirmed || !selectedWalletId) return null;
705
- const selectedOption = walletOptions.find((option) => option.id === selectedWalletId);
1202
+ const selectedOption = walletOptions.find((o) => o.id === selectedWalletId);
706
1203
  if (!selectedOption || !selectedOption.address) return null;
707
1204
  if (selectedOption.kind === "connected" && dappWalletClient?.account && dappWalletClient.account.address.toLowerCase() === selectedOption.address.toLowerCase()) {
708
1205
  return {
@@ -734,6 +1231,131 @@ function WithdrawFlow({
734
1231
  reownWallet,
735
1232
  sourceChain
736
1233
  ]);
1234
+ const ownerAddress = signerContext?.ownerAddress;
1235
+ const recipientForRegistration = useMemo2(() => {
1236
+ if (!recipientInput) return void 0;
1237
+ return ADDR_REGEX.test(recipientInput) ? recipientInput : void 0;
1238
+ }, [recipientInput]);
1239
+ useEffect2(() => {
1240
+ if (!ownerAddress) return;
1241
+ const desiredTarget = {
1242
+ chain: targetChain,
1243
+ token: targetToken,
1244
+ recipient: recipientForRegistration
1245
+ };
1246
+ const current = storeApi.getState().registration;
1247
+ if (current.kind === "ready" && targetsEqual(current.registeredTarget, desiredTarget)) {
1248
+ return;
1249
+ }
1250
+ let cancelled = false;
1251
+ const timeout = setTimeout(async () => {
1252
+ try {
1253
+ storeApi.dispatch({ type: "registration/started" });
1254
+ const sessionOwner = resolveSessionOwner(ownerAddress);
1255
+ if (cancelled) return;
1256
+ logFlow("auto-register:setup", {
1257
+ ownerAddress,
1258
+ targetChain,
1259
+ targetToken,
1260
+ recipient: recipientForRegistration
1261
+ });
1262
+ const setup = await service.setupAccount({
1263
+ ownerAddress,
1264
+ sessionOwnerAddress: sessionOwner.address,
1265
+ targetChain: toEvmCaip2(targetChain),
1266
+ targetToken,
1267
+ recipient: recipientForRegistration,
1268
+ signerAddress,
1269
+ sessionChainIds,
1270
+ forceRegister
1271
+ });
1272
+ if (cancelled) return;
1273
+ if (setup.needsRegistration) {
1274
+ if (!setup.accountParams || !setup.sessionDetailsUnsigned) {
1275
+ throw new Error("Missing registration payload from setup-account");
1276
+ }
1277
+ const typedData = setup.sessionDetailsUnsigned.data;
1278
+ if (!sessionOwner.account.signTypedData) {
1279
+ throw new Error(
1280
+ "Session owner account does not support signTypedData"
1281
+ );
1282
+ }
1283
+ const signature = await sessionOwner.account.signTypedData({
1284
+ domain: typedData.domain,
1285
+ types: typedData.types,
1286
+ primaryType: typedData.primaryType,
1287
+ message: typedData.message
1288
+ });
1289
+ if (cancelled) return;
1290
+ const sessionDetails = buildSessionDetails(
1291
+ setup.sessionDetailsUnsigned,
1292
+ signature
1293
+ );
1294
+ await service.registerAccount({
1295
+ address: setup.smartAccount,
1296
+ accountParams: {
1297
+ factory: setup.accountParams.factory,
1298
+ factoryData: setup.accountParams.factoryData,
1299
+ sessionDetails
1300
+ },
1301
+ eoaAddress: ownerAddress,
1302
+ sessionOwner: sessionOwner.address,
1303
+ target: {
1304
+ chain: toEvmCaip2(targetChain),
1305
+ token: targetToken,
1306
+ recipient: recipientForRegistration
1307
+ }
1308
+ });
1309
+ if (cancelled) return;
1310
+ logFlow("auto-register:registered", {
1311
+ smartAccount: setup.smartAccount
1312
+ });
1313
+ }
1314
+ storeApi.dispatch({
1315
+ type: "registration/ready",
1316
+ smartAccount: setup.smartAccount,
1317
+ registeredTarget: desiredTarget
1318
+ });
1319
+ onLifecycleRef.current?.({
1320
+ type: "connected",
1321
+ address: ownerAddress,
1322
+ smartAccount: setup.smartAccount
1323
+ });
1324
+ } catch (err) {
1325
+ if (cancelled) return;
1326
+ const raw = err instanceof Error ? err.message : "Registration failed";
1327
+ const message = formatUserError(raw);
1328
+ logFlowError("auto-register:failed", err, {
1329
+ ownerAddress,
1330
+ targetChain,
1331
+ targetToken
1332
+ });
1333
+ storeApi.dispatch({
1334
+ type: "registration/failed",
1335
+ error: message
1336
+ });
1337
+ onErrorRef.current?.({ message, code: "WITHDRAW_REGISTER_FAILED" });
1338
+ }
1339
+ }, REGISTRATION_DEBOUNCE_MS);
1340
+ return () => {
1341
+ cancelled = true;
1342
+ clearTimeout(timeout);
1343
+ };
1344
+ }, [
1345
+ ownerAddress,
1346
+ targetChain,
1347
+ targetToken,
1348
+ recipientForRegistration,
1349
+ service,
1350
+ signerAddress,
1351
+ sessionChainIds,
1352
+ forceRegister,
1353
+ storeApi,
1354
+ logFlow,
1355
+ logFlowError,
1356
+ onLifecycleRef,
1357
+ onErrorRef
1358
+ ]);
737
1359
  const asset = useMemo2(() => {
738
1360
  const symbol = getTokenSymbol(sourceToken, sourceChain);
739
1361
  const decimals = getTokenDecimalsByAddress(sourceToken, sourceChain);
@@ -748,60 +1370,51 @@ function WithdrawFlow({
748
1370
  }, [sourceChain, sourceToken]);
749
1371
  const isSourceNative = sourceToken.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();
750
1372
  const isSameRoute = targetChain === sourceChain && targetToken.toLowerCase() === sourceToken.toLowerCase();
751
- const stepIndex = step.type === "form" ? 0 : 1;
752
- const currentBackHandler = void 0;
1373
+ const reviewBackHandler = useCallback2(() => {
1374
+ storeApi.dispatch({ type: "review/back" });
1375
+ }, [storeApi]);
753
1376
  useEffect2(() => {
754
- onStepChangeRef.current?.(stepIndex, currentBackHandler);
755
- }, [stepIndex, currentBackHandler, onStepChangeRef]);
1377
+ onStepChangeRef.current?.(
1378
+ flowStep === "review" ? reviewBackHandler : void 0
1379
+ );
1380
+ }, [flowStep, reviewBackHandler, onStepChangeRef]);
756
1381
  const lastStepOpenEventKeyRef = useRef2(null);
757
1382
  useEffect2(() => {
758
- if (step.type !== "form") {
1383
+ if (flowStep !== "form") {
759
1384
  lastStepOpenEventKeyRef.current = null;
760
1385
  return;
761
1386
  }
762
- if (lastStepOpenEventKeyRef.current === "form") {
763
- return;
764
- }
1387
+ if (lastStepOpenEventKeyRef.current === "form") return;
765
1388
  lastStepOpenEventKeyRef.current = "form";
766
- if (step.type === "form") {
767
- const tokenSymbol = getTokenSymbol(targetToken, targetChain);
768
- const chainName = getChainName(targetChain);
769
- onEventRef.current?.({
770
- type: "withdraw_modal_select_amount_open",
771
- pred_balance: totalBalanceUsd,
772
- default_token: tokenSymbol,
773
- default_chain: chainName
774
- });
775
- }
776
- }, [step.type, targetToken, targetChain, totalBalanceUsd, onEventRef]);
1389
+ const tokenSymbol = getTokenSymbol(targetToken, targetChain);
1390
+ const chainName = getChainName(targetChain);
1391
+ onEventRef.current?.({
1392
+ type: "withdraw_modal_select_amount_open",
1393
+ pred_balance: totalBalanceUsd,
1394
+ default_token: tokenSymbol,
1395
+ default_chain: chainName
1396
+ });
1397
+ }, [flowStep, targetToken, targetChain, totalBalanceUsd, onEventRef]);
777
1398
  useEffect2(() => {
778
1399
  logFlow("state:changed", {
779
- step: step.type,
1400
+ step: flowStep,
780
1401
  sourceChain,
781
1402
  sourceToken,
782
1403
  targetChain,
783
1404
  targetToken,
784
- selectedWalletId
1405
+ selectedWalletId,
1406
+ registration: registration.kind
785
1407
  });
786
1408
  }, [
787
1409
  logFlow,
788
1410
  selectedWalletId,
789
1411
  sourceChain,
790
1412
  sourceToken,
791
- step.type,
1413
+ flowStep,
792
1414
  targetChain,
793
- targetToken
1415
+ targetToken,
1416
+ registration.kind
794
1417
  ]);
795
- useEffect2(() => {
796
- onTotalBalanceChangeRef.current?.(totalBalanceUsd);
797
- }, [totalBalanceUsd, onTotalBalanceChangeRef]);
798
- const handleConnected = useCallback2(
799
- (addr, smartAccount) => {
800
- logFlow("setup:connected", { address: addr, smartAccount });
801
- onConnectedRef.current?.({ address: addr, smartAccount });
802
- },
803
- [logFlow, onConnectedRef]
804
- );
805
1418
  const handleError = useCallback2(
806
1419
  (message, code) => {
807
1420
  logFlowError("flow:error", message, { code });
@@ -809,23 +1422,8 @@ function WithdrawFlow({
809
1422
  },
810
1423
  [logFlowError, onErrorRef]
811
1424
  );
812
- const resolveSessionOwner = useCallback2(async (eoaAddress) => {
813
- const localOwner = loadSessionOwnerFromStorage(eoaAddress);
814
- if (localOwner) {
815
- return {
816
- account: accountFromPrivateKey(localOwner.privateKey),
817
- address: localOwner.address
818
- };
819
- }
820
- const created = createSessionOwnerKey();
821
- saveSessionOwnerToStorage(eoaAddress, created.privateKey, created.address);
822
- return {
823
- account: created.account,
824
- address: created.address
825
- };
826
- }, []);
827
- const handleFormSubmit = useCallback2(
828
- async (recipient, amountValue) => {
1425
+ const handleFormContinue = useCallback2(
1426
+ (recipient, amountValue) => {
829
1427
  const tokenSymbol = getTokenSymbol(targetToken, targetChain);
830
1428
  const chainName = getChainName(targetChain);
831
1429
  onEventRef.current?.({
@@ -836,17 +1434,32 @@ function WithdrawFlow({
836
1434
  amount: amountValue,
837
1435
  cta_name: "withdraw"
838
1436
  });
839
- const ownerAddress2 = signerContext?.ownerAddress;
840
- if (!ownerAddress2) {
841
- throw new Error("Wallet not connected");
1437
+ storeApi.dispatch({
1438
+ type: "form/continue",
1439
+ amount: amountValue,
1440
+ recipient
1441
+ });
1442
+ },
1443
+ [targetToken, targetChain, totalBalanceUsd, onEventRef, storeApi]
1444
+ );
1445
+ const handleReviewConfirm = useCallback2(
1446
+ async () => {
1447
+ const state = storeApi.getState();
1448
+ if (state.registration.kind !== "ready") {
1449
+ throw new Error("Session not ready");
1450
+ }
1451
+ const smartAccount = state.registration.smartAccount;
1452
+ const recipient = state.recipient;
1453
+ const amountValue = state.amount;
1454
+ if (!recipient || !amountValue) {
1455
+ throw new Error("Missing recipient or amount");
842
1456
  }
843
1457
  if (!onSignTransaction && !signerContext?.walletClient) {
844
1458
  throw new Error("Wallet not connected");
845
1459
  }
846
- setIsSubmitting(true);
847
1460
  try {
848
1461
  logFlow("submit:start", {
849
- ownerAddress: ownerAddress2,
1462
+ smartAccount,
850
1463
  recipient,
851
1464
  amount: amountValue,
852
1465
  sourceChain,
@@ -854,60 +1467,6 @@ function WithdrawFlow({
854
1467
  targetChain,
855
1468
  targetToken
856
1469
  });
857
- const sessionOwner = await resolveSessionOwner(ownerAddress2);
858
- const setup = await service.setupAccount({
859
- ownerAddress: ownerAddress2,
860
- sessionOwnerAddress: sessionOwner.address,
861
- targetChain: toEvmCaip2(targetChain),
862
- targetToken,
863
- recipient,
864
- signerAddress,
865
- sessionChainIds,
866
- forceRegister
867
- });
868
- const smartAccount = setup.smartAccount;
869
- logFlow("setup:resolved", {
870
- smartAccount,
871
- needsRegistration: setup.needsRegistration
872
- });
873
- if (setup.needsRegistration) {
874
- if (!setup.accountParams || !setup.sessionDetailsUnsigned) {
875
- throw new Error("Missing registration payload from setup-account");
876
- }
877
- const typedData = setup.sessionDetailsUnsigned.data;
878
- if (!sessionOwner.account.signTypedData) {
879
- throw new Error(
880
- "Session owner account does not support signTypedData"
881
- );
882
- }
883
- const signature = await sessionOwner.account.signTypedData({
884
- domain: typedData.domain,
885
- types: typedData.types,
886
- primaryType: typedData.primaryType,
887
- message: typedData.message
888
- });
889
- const sessionDetails = buildSessionDetails(
890
- setup.sessionDetailsUnsigned,
891
- signature
892
- );
893
- await service.registerAccount({
894
- address: smartAccount,
895
- accountParams: {
896
- factory: setup.accountParams.factory,
897
- factoryData: setup.accountParams.factoryData,
898
- sessionDetails
899
- },
900
- eoaAddress: ownerAddress2,
901
- sessionOwner: sessionOwner.address,
902
- target: {
903
- chain: toEvmCaip2(targetChain),
904
- token: targetToken,
905
- recipient
906
- }
907
- });
908
- logFlow("register:success", { smartAccount });
909
- }
910
- handleConnected(ownerAddress2, smartAccount);
911
1470
  const amountUnits = parseUnits2(amountValue, asset.decimals);
912
1471
  const pc = signerContext?.publicClient ?? getPublicClient(sourceChain);
913
1472
  let result;
@@ -916,8 +1475,8 @@ function WithdrawFlow({
916
1475
  const transferData = isSourceNative ? { to: transferTarget, value: amountUnits, data: "0x" } : {
917
1476
  to: sourceToken,
918
1477
  value: 0n,
919
- data: encodeFunctionData({
920
- abi: erc20Abi2,
1478
+ data: encodeFunctionData2({
1479
+ abi: erc20Abi3,
921
1480
  functionName: "transfer",
922
1481
  args: [transferTarget, amountUnits]
923
1482
  })
@@ -969,21 +1528,14 @@ function WithdrawFlow({
969
1528
  sourceChain,
970
1529
  sourceToken
971
1530
  });
972
- onWithdrawSubmittedRef.current?.({
1531
+ onLifecycleRef.current?.({
1532
+ type: "submitted",
973
1533
  txHash: result.txHash,
974
1534
  sourceChain,
975
1535
  amount: amountUnits.toString(),
976
1536
  safeAddress
977
1537
  });
978
- setStep({
979
- type: "processing",
980
- smartAccount,
981
- txHash: result.txHash,
982
- sourceChain,
983
- sourceToken,
984
- amount: amountUnits.toString(),
985
- directTransfer: isSameRoute
986
- });
1538
+ storeApi.dispatch({ type: "withdraw/submitted", txHash: result.txHash });
987
1539
  } catch (err) {
988
1540
  const raw = err instanceof Error ? err.message : "Withdraw failed";
989
1541
  logFlowError("submit:failed", err, {
@@ -994,20 +1546,13 @@ function WithdrawFlow({
994
1546
  });
995
1547
  handleError(formatUserError(raw), "WITHDRAW_FLOW_ERROR");
996
1548
  throw err;
997
- } finally {
998
- setIsSubmitting(false);
999
1549
  }
1000
1550
  },
1001
1551
  [
1002
1552
  signerContext,
1003
- resolveSessionOwner,
1004
- signerAddress,
1005
- sessionChainIds,
1006
- forceRegister,
1007
1553
  targetChain,
1008
1554
  targetToken,
1009
1555
  service,
1010
- handleConnected,
1011
1556
  asset.decimals,
1012
1557
  safeAddress,
1013
1558
  sourceToken,
@@ -1018,15 +1563,15 @@ function WithdrawFlow({
1018
1563
  handleError,
1019
1564
  logFlow,
1020
1565
  logFlowError,
1021
- onEventRef,
1022
- totalBalanceUsd,
1023
- onWithdrawSubmittedRef
1566
+ onLifecycleRef,
1567
+ storeApi
1024
1568
  ]
1025
1569
  );
1026
1570
  const handleWithdrawComplete = useCallback2(
1027
1571
  (txHash, destinationTxHash, context) => {
1028
1572
  logFlow("withdraw:complete", { txHash, destinationTxHash, ...context });
1029
- onWithdrawCompleteRef.current?.({
1573
+ onLifecycleRef.current?.({
1574
+ type: "complete",
1030
1575
  txHash,
1031
1576
  destinationTxHash,
1032
1577
  amount: context.amount,
@@ -1035,15 +1580,21 @@ function WithdrawFlow({
1035
1580
  targetChain: context.targetChain,
1036
1581
  targetToken: context.targetToken
1037
1582
  });
1583
+ storeApi.dispatch({ type: "withdraw/complete" });
1038
1584
  },
1039
- [logFlow, onWithdrawCompleteRef]
1585
+ [logFlow, onLifecycleRef, storeApi]
1040
1586
  );
1041
1587
  const handleWithdrawFailed = useCallback2(
1042
1588
  (txHash, error) => {
1043
1589
  logFlowError("withdraw:failed", error, { txHash });
1044
- onWithdrawFailedRef.current?.({ txHash, error });
1590
+ onLifecycleRef.current?.({
1591
+ type: "failed",
1592
+ txHash,
1593
+ error
1594
+ });
1595
+ storeApi.dispatch({ type: "withdraw/failed" });
1045
1596
  },
1046
- [logFlowError, onWithdrawFailedRef]
1597
+ [logFlowError, onLifecycleRef, storeApi]
1047
1598
  );
1048
1599
  const allowedChainSet = useMemo2(
1049
1600
  () => allowedRoutes?.sourceChains ? new Set(allowedRoutes.sourceChains) : null,
@@ -1073,20 +1624,18 @@ function WithdrawFlow({
1073
1624
  const matches = targetTokenOptions.some(
1074
1625
  (option) => option.address.toLowerCase() === targetToken.toLowerCase()
1075
1626
  );
1076
- if (!matches) {
1077
- setTargetToken(targetTokenOptions[0].address);
1078
- }
1627
+ if (!matches) setTargetToken(targetTokenOptions[0].address);
1079
1628
  }, [targetToken, targetTokenOptions]);
1080
1629
  const handleTargetChainChange = useCallback2(
1081
1630
  (chainId) => {
1082
1631
  setTargetChain(chainId);
1083
1632
  let options = getSupportedTargetTokens(chainId);
1084
1633
  if (allowedTokenSet) {
1085
- options = options.filter((t) => allowedTokenSet.has(t.symbol.toUpperCase()));
1086
- }
1087
- if (options.length === 0) {
1088
- return;
1634
+ options = options.filter(
1635
+ (t) => allowedTokenSet.has(t.symbol.toUpperCase())
1636
+ );
1089
1637
  }
1638
+ if (options.length === 0) return;
1090
1639
  const currentlySupported = options.some(
1091
1640
  (option) => option.address.toLowerCase() === targetToken.toLowerCase()
1092
1641
  );
@@ -1101,27 +1650,18 @@ function WithdrawFlow({
1101
1650
  }, []);
1102
1651
  const selectedWalletIdEffective = useMemo2(() => {
1103
1652
  if (selectedWalletId) return selectedWalletId;
1104
- if (walletOptions.length === 1) {
1105
- return walletOptions[0].id;
1106
- }
1653
+ if (walletOptions.length === 1) return walletOptions[0].id;
1107
1654
  return null;
1108
1655
  }, [selectedWalletId, walletOptions]);
1109
1656
  const walletOptionsKey = useMemo2(
1110
- () => walletOptions.map((option) => option.id).join(","),
1657
+ () => walletOptions.map((o) => o.id).join(","),
1111
1658
  [walletOptions]
1112
1659
  );
1113
1660
  const showConnectStep = !canAutoLock && !isConnectSelectionConfirmed;
1114
1661
  useEffect2(() => {
1115
1662
  setIsConnectSelectionConfirmed(false);
1116
- }, [walletOptionsKey, selectedWalletIdEffective]);
1117
- useEffect2(() => {
1118
- if (!showConnectStep && isConnectSelectionConfirmed && !signerContext) {
1119
- setSelectedWalletId(null);
1120
- setIsConnectSelectionConfirmed(false);
1121
- }
1122
- }, [showConnectStep, isConnectSelectionConfirmed, signerContext]);
1123
- const ownerAddress = signerContext?.ownerAddress;
1124
- const selectedWalletOption = selectedWalletIdEffective ? walletOptions.find((option) => option.id === selectedWalletIdEffective) ?? null : null;
1663
+ }, [walletOptionsKey]);
1664
+ const selectedWalletOption = selectedWalletIdEffective ? walletOptions.find((o) => o.id === selectedWalletIdEffective) ?? null : null;
1125
1665
  const selectedWalletIcon = useMemo2(() => {
1126
1666
  if (!ownerAddress) return void 0;
1127
1667
  const selected = walletOptions.find(
@@ -1130,18 +1670,19 @@ function WithdrawFlow({
1130
1670
  return selected?.kind === "external" ? selected.icon ?? reownWallet?.icon : void 0;
1131
1671
  }, [walletOptions, ownerAddress, reownWallet?.icon]);
1132
1672
  if (showConnectStep) {
1133
- return /* @__PURE__ */ jsx2("div", { className: "rs-modal-body", children: /* @__PURE__ */ jsx2(
1673
+ return /* @__PURE__ */ jsx3("div", { className: "rs-modal-body", children: /* @__PURE__ */ jsx3(
1134
1674
  ConnectStep,
1135
1675
  {
1136
1676
  walletOptions,
1137
- onSelectWallet: (walletId) => {
1677
+ onConfirmWallet: (walletId) => {
1138
1678
  setSelectedWalletId(walletId);
1139
1679
  setIsConnectSelectionConfirmed(true);
1140
1680
  },
1141
1681
  onRequestConnect,
1142
1682
  onConnect,
1143
1683
  onDisconnect,
1144
- connectButtonLabel
1684
+ title: "Withdraw",
1685
+ subtitle: "Choose a wallet to continue"
1145
1686
  }
1146
1687
  ) });
1147
1688
  }
@@ -1149,8 +1690,9 @@ function WithdrawFlow({
1149
1690
  if (!onSignTransaction && !signerContext.walletClient) return null;
1150
1691
  const resolvedConnectedRecipient = selectedWalletOption?.kind === "external" ? selectedWalletOption.address : void 0;
1151
1692
  const formPublicClient = signerContext.publicClient ?? getPublicClient(sourceChain);
1152
- return /* @__PURE__ */ jsxs2("div", { className: "rs-modal-body", children: [
1153
- step.type === "form" && /* @__PURE__ */ jsx2(
1693
+ const stepView = deriveStepView(flowStep, registration);
1694
+ return /* @__PURE__ */ jsxs3("div", { className: "rs-modal-body", children: [
1695
+ stepView === "form" && /* @__PURE__ */ jsx3(
1154
1696
  WithdrawFormStep,
1155
1697
  {
1156
1698
  walletClient: signerContext.walletClient,
@@ -1168,27 +1710,44 @@ function WithdrawFlow({
1168
1710
  onTargetTokenChange: handleTargetTokenChange,
1169
1711
  switchChain: signerContext.switchChain,
1170
1712
  walletIcon: selectedWalletIcon,
1171
- submitting: isSubmitting,
1172
- onSubmit: handleFormSubmit,
1713
+ registrationPending: registration.kind === "pending" || registration.kind === "stale",
1714
+ registrationError: registration.kind === "failed" ? registration.error : null,
1715
+ onRecipientChange: setRecipientInput,
1716
+ onSubmit: async (r, a) => handleFormContinue(r, a),
1173
1717
  onBalanceUsdChange: setTotalBalanceUsd
1174
1718
  }
1175
1719
  ),
1176
- step.type === "processing" && /* @__PURE__ */ jsx2(
1720
+ stepView === "review" && /* @__PURE__ */ jsx3(
1721
+ WithdrawReviewStep,
1722
+ {
1723
+ sourceChain,
1724
+ sourceSymbol: asset.symbol,
1725
+ targetChain,
1726
+ targetToken,
1727
+ amount: storeApi.getState().amount ?? "0",
1728
+ recipient: storeApi.getState().recipient ?? recipientForRegistration ?? "0x0",
1729
+ registrationPending: registration.kind === "pending" || registration.kind === "stale",
1730
+ registrationError: registration.kind === "failed" ? registration.error : null,
1731
+ onConfirm: handleReviewConfirm,
1732
+ onError: handleError
1733
+ }
1734
+ ),
1735
+ stepView === "processing" && registration.kind !== "idle" && /* @__PURE__ */ jsx3(
1177
1736
  ProcessingStep,
1178
1737
  {
1179
- smartAccount: step.smartAccount,
1180
- txHash: step.txHash,
1181
- sourceChain: step.sourceChain,
1182
- sourceToken: step.sourceToken,
1738
+ smartAccount: registration.kind === "ready" || registration.kind === "stale" ? registration.smartAccount : "0x0",
1739
+ txHash: storeApi.getState().txHash ?? "0x0",
1740
+ sourceChain,
1741
+ sourceToken,
1183
1742
  targetChain,
1184
1743
  targetToken,
1185
- amount: step.amount,
1186
- directTransfer: step.directTransfer,
1744
+ amount: storeApi.getState().amount ?? "0",
1745
+ directTransfer: isSameRoute,
1187
1746
  waitForFinalTx,
1188
1747
  service,
1189
1748
  flowLabel: "withdraw",
1190
1749
  onClose,
1191
- onNewDeposit: () => setStep({ type: "form" }),
1750
+ onNewDeposit: () => storeApi.dispatch({ type: "flow/reset" }),
1192
1751
  onDepositComplete: handleWithdrawComplete,
1193
1752
  onDepositFailed: handleWithdrawFailed,
1194
1753
  onError: handleError,
@@ -1197,20 +1756,27 @@ function WithdrawFlow({
1197
1756
  )
1198
1757
  ] });
1199
1758
  }
1759
+ function deriveStepView(step, _registration) {
1760
+ if (step === "review") return "review";
1761
+ if (step === "processing" || step === "complete" || step === "failed") {
1762
+ return "processing";
1763
+ }
1764
+ return "form";
1765
+ }
1200
1766
 
1201
1767
  // src/WithdrawModal.tsx
1202
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1768
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1203
1769
  var ReownWithdrawInner = lazy(
1204
- () => import("./WithdrawModalReown-HTEB4XGU.mjs").then((m) => ({
1770
+ () => import("./WithdrawModalReown-SQQQV6KQ.mjs").then((m) => ({
1205
1771
  default: m.WithdrawModalReown
1206
1772
  }))
1207
1773
  );
1208
1774
  function WithdrawModal(props) {
1209
1775
  const needsReown = !!props.reownAppId;
1210
1776
  if (needsReown) {
1211
- return /* @__PURE__ */ jsx3(Suspense, { fallback: null, children: /* @__PURE__ */ jsx3(ReownWithdrawInner, { ...props }) });
1777
+ return /* @__PURE__ */ jsx4(Suspense, { fallback: null, children: /* @__PURE__ */ jsx4(ReownWithdrawInner, { ...props }) });
1212
1778
  }
1213
- return /* @__PURE__ */ jsx3(WithdrawModalInner, { ...props });
1779
+ return /* @__PURE__ */ jsx4(WithdrawModalInner, { ...props });
1214
1780
  }
1215
1781
  WithdrawModal.displayName = "WithdrawModal";
1216
1782
  function WithdrawModalInner({
@@ -1239,31 +1805,36 @@ function WithdrawModalInner({
1239
1805
  onDisconnect,
1240
1806
  onSignTransaction,
1241
1807
  onRequestConnect,
1242
- connectButtonLabel,
1243
1808
  theme,
1244
- branding,
1245
1809
  uiConfig,
1246
1810
  className,
1247
1811
  onReady,
1248
- onConnected,
1249
- onWithdrawSubmitted,
1250
- onWithdrawComplete,
1251
- onWithdrawFailed,
1812
+ onLifecycle,
1252
1813
  onEvent,
1253
1814
  onError,
1254
1815
  debug
1255
1816
  }) {
1256
1817
  const modalRef = useRef3(null);
1257
1818
  const onReadyRef = useLatestRef(onReady);
1258
- const [currentStepIndex, setCurrentStepIndex] = useState3(0);
1259
- const [totalBalanceUsd, setTotalBalanceUsd] = useState3(null);
1260
- const backHandlerRef = useRef3(void 0);
1819
+ const [backHandler, setBackHandler] = useState4(
1820
+ void 0
1821
+ );
1261
1822
  const targetChain = getChainId(targetChainProp);
1262
1823
  const sourceChain = getChainId(sourceChainProp);
1263
1824
  const service = useMemo3(
1264
1825
  () => createDepositService(backendUrl, { debug, debugScope: "service:withdraw" }),
1265
1826
  [backendUrl, debug]
1266
1827
  );
1828
+ const store = useMemo3(() => createWithdrawStore(), []);
1829
+ const onErrorRef = useLatestRef(onError);
1830
+ useEffect3(() => {
1831
+ if (isOpen && onSignTransaction && !dappAddress) {
1832
+ onErrorRef.current?.({
1833
+ message: "WithdrawModal requires `dappAddress` when `onSignTransaction` is provided.",
1834
+ code: "WITHDRAW_MISSING_DAPP_ADDRESS"
1835
+ });
1836
+ }
1837
+ }, [isOpen, onSignTransaction, dappAddress, onErrorRef]);
1267
1838
  useEffect3(() => {
1268
1839
  if (isOpen && modalRef.current) {
1269
1840
  applyTheme(modalRef.current, theme);
@@ -1276,30 +1847,15 @@ function WithdrawModalInner({
1276
1847
  }, [isOpen, onReadyRef]);
1277
1848
  useEffect3(() => {
1278
1849
  if (!isOpen) {
1279
- setCurrentStepIndex(0);
1850
+ store.dispatch({ type: "modal/reset" });
1280
1851
  }
1281
- }, [isOpen]);
1282
- const handleStepChange = useCallback3(
1283
- (stepIndex, onBack) => {
1284
- setCurrentStepIndex(stepIndex);
1285
- backHandlerRef.current = onBack;
1286
- },
1287
- []
1288
- );
1289
- const handleTotalBalanceChange = useCallback3((balance2) => {
1290
- setTotalBalanceUsd(balance2);
1291
- }, []);
1292
- const handleBack = useCallback3(() => {
1293
- backHandlerRef.current?.();
1852
+ }, [isOpen, store]);
1853
+ const handleStepChange = useCallback3((onBack) => {
1854
+ setBackHandler(() => onBack);
1294
1855
  }, []);
1295
- const showLogo = uiConfig?.showLogo ?? false;
1296
- const showStepper = uiConfig?.showStepper ?? false;
1297
1856
  const showBackButton = uiConfig?.showBackButton ?? true;
1298
- const balance = uiConfig?.balance;
1299
- const logoUrl = branding?.logoUrl ?? "https://github.com/rhinestonewtf.png";
1300
- const title = branding?.title ?? "Withdraw";
1301
- const canGoBack = currentStepIndex > 0 && currentStepIndex < 3 && backHandlerRef.current;
1302
- return /* @__PURE__ */ jsx3(
1857
+ const canGoBack = backHandler !== void 0;
1858
+ return /* @__PURE__ */ jsx4(WithdrawStoreProvider, { store, children: /* @__PURE__ */ jsx4(
1303
1859
  Modal,
1304
1860
  {
1305
1861
  isOpen,
@@ -1307,89 +1863,30 @@ function WithdrawModalInner({
1307
1863
  className,
1308
1864
  inline,
1309
1865
  closeOnOverlayClick,
1310
- children: /* @__PURE__ */ jsxs3("div", { ref: modalRef, className: "rs-modal", children: [
1311
- /* @__PURE__ */ jsxs3("div", { className: "rs-modal-header--redesigned", children: [
1312
- /* @__PURE__ */ jsx3("div", { className: "rs-modal-header-nav-left", children: showBackButton && canGoBack && /* @__PURE__ */ jsx3(
1866
+ children: /* @__PURE__ */ jsxs4("div", { ref: modalRef, className: "rs-modal", children: [
1867
+ /* @__PURE__ */ jsxs4("div", { className: "rs-modal-header--redesigned", children: [
1868
+ /* @__PURE__ */ jsx4("div", { className: "rs-modal-header-nav-left", children: showBackButton && canGoBack && backHandler && /* @__PURE__ */ jsx4(
1313
1869
  "button",
1314
1870
  {
1315
1871
  type: "button",
1316
1872
  className: "rs-modal-header-back",
1317
1873
  "aria-label": "Go back",
1318
- onClick: handleBack,
1319
- children: /* @__PURE__ */ jsx3(
1320
- "svg",
1321
- {
1322
- viewBox: "0 0 24 24",
1323
- fill: "none",
1324
- stroke: "currentColor",
1325
- strokeWidth: "2",
1326
- children: /* @__PURE__ */ jsx3(
1327
- "path",
1328
- {
1329
- strokeLinecap: "round",
1330
- strokeLinejoin: "round",
1331
- d: "M15.75 19.5L8.25 12l7.5-7.5"
1332
- }
1333
- )
1334
- }
1335
- )
1874
+ onClick: backHandler,
1875
+ children: /* @__PURE__ */ jsx4(ChevronLeftIcon, {})
1336
1876
  }
1337
1877
  ) }),
1338
- /* @__PURE__ */ jsxs3("div", { className: "rs-modal-header-nav-center", children: [
1339
- /* @__PURE__ */ jsxs3("div", { className: "rs-modal-header-title-row", children: [
1340
- showLogo && logoUrl && /* @__PURE__ */ jsx3(
1341
- "img",
1342
- {
1343
- src: logoUrl,
1344
- alt: "",
1345
- className: "rs-modal-logo",
1346
- onError: (e) => {
1347
- e.target.style.display = "none";
1348
- }
1349
- }
1350
- ),
1351
- /* @__PURE__ */ jsx3("span", { className: "rs-modal-header-title", children: title }),
1352
- showStepper && /* @__PURE__ */ jsx3("div", { className: "rs-modal-progress", style: { marginLeft: 8 }, children: [0, 1].map((i) => /* @__PURE__ */ jsx3(
1353
- "div",
1354
- {
1355
- className: `rs-modal-progress-dot ${i <= currentStepIndex ? "rs-modal-progress-dot--active" : "rs-modal-progress-dot--inactive"}`
1356
- },
1357
- i
1358
- )) })
1359
- ] }),
1360
- balance && /* @__PURE__ */ jsxs3("div", { className: "rs-modal-header-balance", children: [
1361
- /* @__PURE__ */ jsx3("span", { className: "rs-modal-header-balance-label", children: balance.title }),
1362
- /* @__PURE__ */ jsx3("span", { className: "rs-modal-header-balance-value", children: balance.amount ?? (totalBalanceUsd !== null ? currencyFormatter.format(totalBalanceUsd) : null) })
1363
- ] })
1364
- ] }),
1365
- /* @__PURE__ */ jsx3("div", { className: "rs-modal-header-nav-right", children: /* @__PURE__ */ jsx3(
1878
+ /* @__PURE__ */ jsx4("div", { className: "rs-modal-header-nav-right", children: /* @__PURE__ */ jsx4(
1366
1879
  "button",
1367
1880
  {
1368
1881
  type: "button",
1369
1882
  onClick: onClose,
1370
1883
  className: "rs-modal-close",
1371
1884
  "aria-label": "Close",
1372
- children: /* @__PURE__ */ jsx3(
1373
- "svg",
1374
- {
1375
- viewBox: "0 0 24 24",
1376
- fill: "none",
1377
- stroke: "currentColor",
1378
- strokeWidth: "2",
1379
- children: /* @__PURE__ */ jsx3(
1380
- "path",
1381
- {
1382
- strokeLinecap: "round",
1383
- strokeLinejoin: "round",
1384
- d: "M6 18L18 6M6 6l12 12"
1385
- }
1386
- )
1387
- }
1388
- )
1885
+ children: /* @__PURE__ */ jsx4(CloseIcon, {})
1389
1886
  }
1390
1887
  ) })
1391
1888
  ] }),
1392
- /* @__PURE__ */ jsx3(
1889
+ /* @__PURE__ */ jsx4(
1393
1890
  WithdrawFlow,
1394
1891
  {
1395
1892
  dappWalletClient,
@@ -1413,14 +1910,9 @@ function WithdrawModalInner({
1413
1910
  onDisconnect,
1414
1911
  onSignTransaction,
1415
1912
  onRequestConnect,
1416
- connectButtonLabel,
1417
1913
  onStepChange: handleStepChange,
1418
- onTotalBalanceChange: handleTotalBalanceChange,
1419
1914
  onClose,
1420
- onConnected,
1421
- onWithdrawSubmitted,
1422
- onWithdrawComplete,
1423
- onWithdrawFailed,
1915
+ onLifecycle,
1424
1916
  onEvent,
1425
1917
  onError,
1426
1918
  debug
@@ -1428,7 +1920,7 @@ function WithdrawModalInner({
1428
1920
  )
1429
1921
  ] })
1430
1922
  }
1431
- );
1923
+ ) });
1432
1924
  }
1433
1925
 
1434
1926
  export {