@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.
- package/README.md +40 -211
- package/dist/{DepositModalReown-GIODYNOK.mjs → DepositModalReown-EESTTLN4.mjs} +3 -5
- package/dist/{DepositModalReown-SVVA3OZ6.cjs → DepositModalReown-VV3H2WWC.cjs} +4 -6
- package/dist/QRCode-SMMYPUQC.cjs +58 -0
- package/dist/QRCode-YMQTKSSK.mjs +58 -0
- package/dist/{WithdrawModalReown-VNTKGALT.cjs → WithdrawModalReown-IP4MOGER.cjs} +4 -5
- package/dist/{WithdrawModalReown-HTEB4XGU.mjs → WithdrawModalReown-SQQQV6KQ.mjs} +3 -4
- package/dist/{chunk-AHQY2O3U.cjs → chunk-C6JK3IO6.cjs} +1731 -2161
- package/dist/{chunk-WA4RA4HB.mjs → chunk-D5YCALVX.mjs} +918 -426
- package/dist/{chunk-KE6CJVOV.cjs → chunk-DCAANLEP.cjs} +1110 -817
- package/dist/{chunk-DUGDAMAF.mjs → chunk-FY76DWPD.mjs} +1089 -796
- package/dist/{chunk-R2HP743T.cjs → chunk-IVTXEYB2.cjs} +65 -65
- package/dist/{chunk-4S262VLP.cjs → chunk-K7MNFNR7.cjs} +967 -475
- package/dist/{chunk-RQ2VCKLS.mjs → chunk-SLLI7SB6.mjs} +1815 -2245
- package/dist/{chunk-WHW3ZMOT.mjs → chunk-VA3ANS7D.mjs} +114 -114
- package/dist/constants.cjs +2 -2
- package/dist/constants.d.cts +3 -2
- package/dist/constants.d.ts +3 -2
- package/dist/constants.mjs +1 -1
- package/dist/deposit.cjs +4 -6
- package/dist/deposit.d.cts +2 -3
- package/dist/deposit.d.ts +2 -3
- package/dist/deposit.mjs +3 -5
- package/dist/index.cjs +5 -7
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.mjs +4 -6
- package/dist/styles.css +1068 -752
- package/dist/{types-D0NawmZ8.d.cts → types-DRou84ZM.d.cts} +147 -40
- package/dist/{types-CeFbJ-MW.d.ts → types-DRou84ZM.d.ts} +147 -40
- package/dist/withdraw.cjs +4 -5
- package/dist/withdraw.d.cts +2 -3
- package/dist/withdraw.d.ts +2 -3
- package/dist/withdraw.mjs +3 -4
- package/package.json +13 -12
- package/dist/chunk-J2SWZSXL.mjs +0 -295
- package/dist/chunk-LHOHM67Z.mjs +0 -234
- package/dist/chunk-YKGL66EF.cjs +0 -295
- package/dist/chunk-ZHLQMSQM.cjs +0 -234
- package/dist/reown.cjs +0 -18
- package/dist/reown.d.cts +0 -10
- package/dist/reown.d.ts +0 -10
- package/dist/reown.mjs +0 -18
- package/dist/safe-CB7TvRCc.d.cts +0 -62
- package/dist/safe-CB7TvRCc.d.ts +0 -62
- package/dist/safe.cjs +0 -22
- package/dist/safe.d.cts +0 -14
- package/dist/safe.d.ts +0 -14
- 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-
|
|
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-
|
|
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
|
|
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
|
|
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
|
-
|
|
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__ */
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
"button",
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
394
|
-
|
|
497
|
+
setShowChainDropdown(!showChainDropdown);
|
|
498
|
+
setShowTokenDropdown(false);
|
|
395
499
|
},
|
|
396
500
|
children: [
|
|
397
501
|
/* @__PURE__ */ jsxs("div", { className: "rs-withdraw-dropdown-value", children: [
|
|
398
|
-
|
|
502
|
+
getChainIcon(targetChain) && /* @__PURE__ */ jsx(
|
|
399
503
|
"img",
|
|
400
504
|
{
|
|
401
|
-
src:
|
|
402
|
-
alt:
|
|
505
|
+
src: getChainIcon(targetChain),
|
|
506
|
+
alt: targetChainName,
|
|
403
507
|
className: "rs-withdraw-dropdown-icon"
|
|
404
508
|
}
|
|
405
509
|
),
|
|
406
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
510
|
+
/* @__PURE__ */ jsx("span", { children: targetChainName })
|
|
407
511
|
] }),
|
|
408
512
|
/* @__PURE__ */ jsx(
|
|
409
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
439
|
-
|
|
530
|
+
onTargetChainChange(chain.id);
|
|
531
|
+
setShowChainDropdown(false);
|
|
440
532
|
},
|
|
441
533
|
children: [
|
|
442
|
-
|
|
534
|
+
getChainIcon(chain.id) && /* @__PURE__ */ jsx(
|
|
443
535
|
"img",
|
|
444
536
|
{
|
|
445
|
-
src:
|
|
446
|
-
alt:
|
|
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:
|
|
542
|
+
/* @__PURE__ */ jsx("span", { children: chain.name })
|
|
451
543
|
]
|
|
452
544
|
},
|
|
453
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
474
|
-
|
|
565
|
+
setShowTokenDropdown(!showTokenDropdown);
|
|
566
|
+
setShowChainDropdown(false);
|
|
475
567
|
},
|
|
476
568
|
children: [
|
|
477
569
|
/* @__PURE__ */ jsxs("div", { className: "rs-withdraw-dropdown-value", children: [
|
|
478
|
-
|
|
570
|
+
getTokenIcon(targetSymbol) && /* @__PURE__ */ jsx(
|
|
479
571
|
"img",
|
|
480
572
|
{
|
|
481
|
-
src:
|
|
482
|
-
alt:
|
|
573
|
+
src: getTokenIcon(targetSymbol),
|
|
574
|
+
alt: targetSymbol,
|
|
483
575
|
className: "rs-withdraw-dropdown-icon"
|
|
484
576
|
}
|
|
485
577
|
),
|
|
486
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
578
|
+
/* @__PURE__ */ jsx("span", { children: targetSymbol })
|
|
487
579
|
] }),
|
|
488
580
|
/* @__PURE__ */ jsx(
|
|
489
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
519
|
-
|
|
598
|
+
onTargetTokenChange(option.address);
|
|
599
|
+
setShowTokenDropdown(false);
|
|
520
600
|
},
|
|
521
601
|
children: [
|
|
522
|
-
|
|
602
|
+
getTokenIcon(option.symbol) && /* @__PURE__ */ jsx(
|
|
523
603
|
"img",
|
|
524
604
|
{
|
|
525
|
-
src:
|
|
526
|
-
alt:
|
|
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:
|
|
610
|
+
/* @__PURE__ */ jsx("span", { children: option.symbol })
|
|
531
611
|
]
|
|
532
612
|
},
|
|
533
|
-
|
|
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/
|
|
578
|
-
import {
|
|
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
|
-
|
|
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
|
|
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] =
|
|
639
|
-
const [targetToken, setTargetToken] =
|
|
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
|
|
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
|
|
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((
|
|
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
|
|
752
|
-
|
|
1373
|
+
const reviewBackHandler = useCallback2(() => {
|
|
1374
|
+
storeApi.dispatch({ type: "review/back" });
|
|
1375
|
+
}, [storeApi]);
|
|
753
1376
|
useEffect2(() => {
|
|
754
|
-
onStepChangeRef.current?.(
|
|
755
|
-
|
|
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 (
|
|
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
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
813
|
-
|
|
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
|
-
|
|
840
|
-
|
|
841
|
-
|
|
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
|
-
|
|
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:
|
|
920
|
-
abi:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1022
|
-
|
|
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
|
-
|
|
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,
|
|
1585
|
+
[logFlow, onLifecycleRef, storeApi]
|
|
1040
1586
|
);
|
|
1041
1587
|
const handleWithdrawFailed = useCallback2(
|
|
1042
1588
|
(txHash, error) => {
|
|
1043
1589
|
logFlowError("withdraw:failed", error, { txHash });
|
|
1044
|
-
|
|
1590
|
+
onLifecycleRef.current?.({
|
|
1591
|
+
type: "failed",
|
|
1592
|
+
txHash,
|
|
1593
|
+
error
|
|
1594
|
+
});
|
|
1595
|
+
storeApi.dispatch({ type: "withdraw/failed" });
|
|
1045
1596
|
},
|
|
1046
|
-
[logFlowError,
|
|
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(
|
|
1086
|
-
|
|
1087
|
-
|
|
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((
|
|
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
|
|
1117
|
-
|
|
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__ */
|
|
1673
|
+
return /* @__PURE__ */ jsx3("div", { className: "rs-modal-body", children: /* @__PURE__ */ jsx3(
|
|
1134
1674
|
ConnectStep,
|
|
1135
1675
|
{
|
|
1136
1676
|
walletOptions,
|
|
1137
|
-
|
|
1677
|
+
onConfirmWallet: (walletId) => {
|
|
1138
1678
|
setSelectedWalletId(walletId);
|
|
1139
1679
|
setIsConnectSelectionConfirmed(true);
|
|
1140
1680
|
},
|
|
1141
1681
|
onRequestConnect,
|
|
1142
1682
|
onConnect,
|
|
1143
1683
|
onDisconnect,
|
|
1144
|
-
|
|
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
|
-
|
|
1153
|
-
|
|
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
|
-
|
|
1172
|
-
|
|
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
|
-
|
|
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:
|
|
1180
|
-
txHash:
|
|
1181
|
-
sourceChain
|
|
1182
|
-
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:
|
|
1186
|
-
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: () =>
|
|
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
|
|
1768
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1203
1769
|
var ReownWithdrawInner = lazy(
|
|
1204
|
-
() => import("./WithdrawModalReown-
|
|
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__ */
|
|
1777
|
+
return /* @__PURE__ */ jsx4(Suspense, { fallback: null, children: /* @__PURE__ */ jsx4(ReownWithdrawInner, { ...props }) });
|
|
1212
1778
|
}
|
|
1213
|
-
return /* @__PURE__ */
|
|
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
|
-
|
|
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 [
|
|
1259
|
-
|
|
1260
|
-
|
|
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
|
-
|
|
1850
|
+
store.dispatch({ type: "modal/reset" });
|
|
1280
1851
|
}
|
|
1281
|
-
}, [isOpen]);
|
|
1282
|
-
const handleStepChange = useCallback3(
|
|
1283
|
-
(
|
|
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
|
|
1299
|
-
|
|
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__ */
|
|
1311
|
-
/* @__PURE__ */
|
|
1312
|
-
/* @__PURE__ */
|
|
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:
|
|
1319
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
-
|
|
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 {
|