@ab-org/predicate-market-sdk 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/index.d.ts +672 -22
  2. package/dist/index.js +4700 -23
  3. package/package.json +6 -5
  4. package/dist/auth/autoReconnect.d.ts +0 -11
  5. package/dist/auth/autoReconnect.js +0 -36
  6. package/dist/auth/bundledConfig.d.ts +0 -2
  7. package/dist/auth/bundledConfig.js +0 -19
  8. package/dist/auth/config.d.ts +0 -29
  9. package/dist/auth/config.js +0 -53
  10. package/dist/auth/google.d.ts +0 -43
  11. package/dist/auth/google.js +0 -147
  12. package/dist/auth/oidcRelay.d.ts +0 -11
  13. package/dist/auth/oidcRelay.js +0 -107
  14. package/dist/auth/twitter.d.ts +0 -7
  15. package/dist/auth/twitter.js +0 -94
  16. package/dist/auth/walletAccount.d.ts +0 -20
  17. package/dist/auth/walletAccount.js +0 -267
  18. package/dist/constants/chains.d.ts +0 -2
  19. package/dist/constants/chains.js +0 -3
  20. package/dist/modules/api.d.ts +0 -149
  21. package/dist/modules/api.js +0 -95
  22. package/dist/modules/balanceQuery.d.ts +0 -27
  23. package/dist/modules/balanceQuery.js +0 -60
  24. package/dist/modules/deposit.d.ts +0 -31
  25. package/dist/modules/deposit.js +0 -58
  26. package/dist/modules/marketData.d.ts +0 -8
  27. package/dist/modules/marketData.js +0 -107
  28. package/dist/modules/withdraw.d.ts +0 -31
  29. package/dist/modules/withdraw.js +0 -61
  30. package/dist/modules/withdrawDirect.d.ts +0 -14
  31. package/dist/modules/withdrawDirect.js +0 -33
  32. package/dist/modules/withdrawExecutor.d.ts +0 -56
  33. package/dist/modules/withdrawExecutor.js +0 -210
  34. package/dist/policyAdapter.d.ts +0 -11
  35. package/dist/policyAdapter.js +0 -38
  36. package/dist/types.d.ts +0 -62
  37. package/dist/types.js +0 -1
  38. package/dist/ui/DepositModal.d.ts +0 -36
  39. package/dist/ui/DepositModal.js +0 -354
  40. package/dist/ui/SignInModal.d.ts +0 -22
  41. package/dist/ui/SignInModal.js +0 -77
  42. package/dist/ui/SignInModal.sections.d.ts +0 -33
  43. package/dist/ui/SignInModal.sections.js +0 -45
  44. package/dist/ui/SignInModal.shared.d.ts +0 -15
  45. package/dist/ui/SignInModal.shared.js +0 -126
  46. package/dist/ui/WalletSelectionModal.d.ts +0 -14
  47. package/dist/ui/WalletSelectionModal.js +0 -54
  48. package/dist/ui/WithdrawModal.d.ts +0 -57
  49. package/dist/ui/WithdrawModal.js +0 -574
  50. package/dist/ui/components/CloseButton.d.ts +0 -4
  51. package/dist/ui/components/CloseButton.js +0 -15
  52. package/dist/ui/components/Countdown.d.ts +0 -16
  53. package/dist/ui/components/Countdown.js +0 -42
  54. package/dist/ui/components/DepositDetailsPanel.d.ts +0 -8
  55. package/dist/ui/components/DepositDetailsPanel.js +0 -143
  56. package/dist/ui/components/DropdownField.d.ts +0 -19
  57. package/dist/ui/components/DropdownField.js +0 -81
  58. package/dist/ui/components/Field.d.ts +0 -10
  59. package/dist/ui/components/Field.js +0 -21
  60. package/dist/ui/components/LoginRequiredOverlay.d.ts +0 -6
  61. package/dist/ui/components/LoginRequiredOverlay.js +0 -31
  62. package/dist/ui/components/ModalCard.d.ts +0 -9
  63. package/dist/ui/components/ModalCard.js +0 -14
  64. package/dist/ui/components/ModalFrame.d.ts +0 -9
  65. package/dist/ui/components/ModalFrame.js +0 -18
  66. package/dist/ui/components/PrimaryButton.d.ts +0 -2
  67. package/dist/ui/components/PrimaryButton.js +0 -14
  68. package/dist/ui/components/QRCodePanel.d.ts +0 -4
  69. package/dist/ui/components/QRCodePanel.js +0 -43
  70. package/dist/ui/components/Select.d.ts +0 -12
  71. package/dist/ui/components/Select.js +0 -29
  72. package/dist/ui/components/StepIndicator.d.ts +0 -7
  73. package/dist/ui/components/StepIndicator.js +0 -35
  74. package/dist/ui/components/Success.d.ts +0 -1
  75. package/dist/ui/components/Success.js +0 -4
  76. package/dist/ui/components/Toast.d.ts +0 -8
  77. package/dist/ui/components/Toast.js +0 -51
  78. package/dist/ui/hooks/useSession.d.ts +0 -2
  79. package/dist/ui/hooks/useSession.js +0 -10
  80. package/dist/ui/signInTypes.d.ts +0 -28
  81. package/dist/ui/signInTypes.js +0 -1
  82. package/dist/ui/theme.d.ts +0 -31
  83. package/dist/ui/theme.js +0 -31
  84. package/dist/ui/useSignInModalController.d.ts +0 -25
  85. package/dist/ui/useSignInModalController.js +0 -119
  86. package/dist/utils/env.d.ts +0 -1
  87. package/dist/utils/env.js +0 -63
  88. package/dist/utils/explorer.d.ts +0 -3
  89. package/dist/utils/explorer.js +0 -47
  90. package/dist/walletUtils.d.ts +0 -3
  91. package/dist/walletUtils.js +0 -3
package/dist/index.js CHANGED
@@ -1,23 +1,4700 @@
1
- export * from "./types.js";
2
- export * from "./auth/config.js";
3
- export * from "./auth/autoReconnect.js";
4
- export * from "./auth/google.js";
5
- export * from "./auth/twitter.js";
6
- export * from "./modules/deposit.js";
7
- export * from "./modules/withdraw.js";
8
- export * from "./modules/marketData.js";
9
- export * from "./modules/balanceQuery.js";
10
- export * from "./modules/withdrawExecutor.js";
11
- export * from "./modules/api.js";
12
- export * from "./modules/withdrawDirect.js";
13
- export * from "./policyAdapter.js";
14
- export * from "./ui/SignInModal.js";
15
- export * from "./ui/signInTypes.js";
16
- export * from "./ui/WalletSelectionModal.js";
17
- export * from "./ui/DepositModal.js";
18
- export * from "./ui/WithdrawModal.js";
19
- export * from "./ui/components/DropdownField.js";
20
- export * from "./ui/components/DepositDetailsPanel.js";
21
- export * from "./walletUtils.js";
22
- // Re-export funding chain helpers so apps can import from package root
23
- export * from "./constants/chains.js";
1
+ import { sessionStore, createDefaultInjectedWalletRegistry, CubistSocialProvider, WalletConnector, createSessionCapabilityPolicy, CubeSignerAuth, createChainContext } from '@ab-org/sdk-core';
2
+ import { toHex, fromHex, parseGwei, formatUnits } from 'viem';
3
+ import axios from 'axios';
4
+ import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
5
+ import { EvmSigner } from '@cubist-labs/cubesigner-sdk';
6
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
+ import qrcode from 'qrcode-generator';
8
+
9
+ // src/utils/env.ts
10
+ function pick(...candidates) {
11
+ for (const candidate of candidates) {
12
+ if (candidate != null && candidate !== "") return candidate;
13
+ }
14
+ return void 0;
15
+ }
16
+ function nextPublicProcessEnvKey(logicalKey) {
17
+ return `NEXT_PUBLIC_${logicalKey}`;
18
+ }
19
+ function readProcessEnvStatic(key) {
20
+ if (typeof process === "undefined" || !process.env) return void 0;
21
+ switch (key) {
22
+ case "STAGE":
23
+ return pick(process.env.NEXT_PUBLIC_STAGE, process.env.STAGE);
24
+ case "GOOGLE_CLIENT_ID":
25
+ return pick(process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_ID);
26
+ case "X_CLIENT_ID":
27
+ return pick(process.env.NEXT_PUBLIC_X_CLIENT_ID, process.env.X_CLIENT_ID);
28
+ case "MERCHANT_BASE_URL":
29
+ return pick(process.env.NEXT_PUBLIC_MERCHANT_BASE_URL, process.env.MERCHANT_BASE_URL);
30
+ case "CUBE_SIGNER_ENV":
31
+ return pick(process.env.NEXT_PUBLIC_CUBE_SIGNER_ENV, process.env.CUBE_SIGNER_ENV);
32
+ case "CUBE_SIGNER_ORG_ID":
33
+ return pick(process.env.NEXT_PUBLIC_CUBE_SIGNER_ORG_ID, process.env.CUBE_SIGNER_ORG_ID);
34
+ case "CUBE_REG":
35
+ return pick(process.env.NEXT_PUBLIC_CUBE_REG, process.env.CUBE_REG);
36
+ case "RELAY_ORIGIN":
37
+ return pick(process.env.NEXT_PUBLIC_RELAY_ORIGIN, process.env.RELAY_ORIGIN);
38
+ case "FUNDING_TOKEN_SYMBOL":
39
+ return pick(process.env.NEXT_PUBLIC_FUNDING_TOKEN_SYMBOL, process.env.FUNDING_TOKEN_SYMBOL) || "USDT";
40
+ default:
41
+ return void 0;
42
+ }
43
+ }
44
+ function getEnv(key) {
45
+ const staticVal = readProcessEnvStatic(key);
46
+ if (staticVal != null && staticVal !== "") return staticVal;
47
+ const globalEnv = globalThis.process?.env;
48
+ if (globalEnv) {
49
+ const pub = nextPublicProcessEnvKey(key);
50
+ const val = globalEnv[key] ?? globalEnv[pub];
51
+ if (val != null && val !== "") return val;
52
+ }
53
+ try {
54
+ const metaEnv = import.meta.env;
55
+ if (metaEnv) {
56
+ const pub = nextPublicProcessEnvKey(key);
57
+ const val = metaEnv[key] ?? metaEnv[pub];
58
+ if (val != null && val !== "") return val;
59
+ }
60
+ } catch {
61
+ }
62
+ console.error(`${key} is not set`);
63
+ return "";
64
+ }
65
+
66
+ // src/auth/bundledConfig.ts
67
+ function readOptionalEnv(key) {
68
+ const value = getEnv(key);
69
+ return value === "" ? void 0 : value;
70
+ }
71
+ var relayOrigin = readOptionalEnv("RELAY_ORIGIN");
72
+ var cubeEnv = readOptionalEnv("CUBE_SIGNER_ENV");
73
+ var cubeOrgId = readOptionalEnv("CUBE_SIGNER_ORG_ID");
74
+ var BUNDLED_AUTH_CONFIG = {
75
+ googleClientId: readOptionalEnv("GOOGLE_CLIENT_ID"),
76
+ twitterClientId: readOptionalEnv("X_CLIENT_ID"),
77
+ twitterRedirectUri: relayOrigin ? `${relayOrigin}/auth/twitter-callback` : void 0,
78
+ cubeSigner: cubeEnv && cubeOrgId ? {
79
+ env: cubeEnv,
80
+ orgId: cubeOrgId
81
+ } : void 0
82
+ };
83
+ var pending = null;
84
+ function tryAutoReconnect() {
85
+ const session = sessionStore.getState().session;
86
+ if (!session) return Promise.resolve(null);
87
+ if (pending) return pending;
88
+ pending = doAutoReconnect().finally(() => {
89
+ pending = null;
90
+ });
91
+ return pending;
92
+ }
93
+ async function doAutoReconnect() {
94
+ const config = getSDKConfig();
95
+ const registry = createDefaultInjectedWalletRegistry();
96
+ const adapters = [...registry.map((r) => r.provider)];
97
+ if (config.cubeSigner) {
98
+ adapters.push(
99
+ new CubistSocialProvider({
100
+ ...config.cubeSigner,
101
+ defaultSessionPolicy: config.signIn?.sessionPolicy ?? config.cubeSigner.defaultSessionPolicy
102
+ })
103
+ );
104
+ }
105
+ const connector = new WalletConnector(adapters);
106
+ return connector.tryAutoReconnect();
107
+ }
108
+
109
+ // src/auth/config.ts
110
+ var sdkConfig = {};
111
+ function readOptionalEnv2(key) {
112
+ const value = getEnv(key);
113
+ return value === "" ? void 0 : value;
114
+ }
115
+ function getFixedAuthConfig() {
116
+ const envGoogle = readOptionalEnv2("GOOGLE_CLIENT_ID");
117
+ const envTwitter = readOptionalEnv2("X_CLIENT_ID");
118
+ const relayOrigin2 = readOptionalEnv2("RELAY_ORIGIN");
119
+ const envRedirect = relayOrigin2 ? `${relayOrigin2}/auth/twitter-callback` : void 0;
120
+ const cubeEnv2 = readOptionalEnv2("CUBE_SIGNER_ENV");
121
+ const cubeOrgId2 = readOptionalEnv2("CUBE_SIGNER_ORG_ID");
122
+ const cubeSignerFromEnv = cubeEnv2 && cubeOrgId2 ? { env: cubeEnv2, orgId: cubeOrgId2 } : void 0;
123
+ return {
124
+ googleClientId: envGoogle || BUNDLED_AUTH_CONFIG.googleClientId,
125
+ twitterClientId: envTwitter || BUNDLED_AUTH_CONFIG.twitterClientId,
126
+ twitterRedirectUri: envRedirect || BUNDLED_AUTH_CONFIG.twitterRedirectUri,
127
+ cubeSigner: cubeSignerFromEnv ?? BUNDLED_AUTH_CONFIG.cubeSigner
128
+ };
129
+ }
130
+ function initSDK(config = {}) {
131
+ const { registerUser, ...rest } = config;
132
+ const fixed = getFixedAuthConfig();
133
+ const merged = {
134
+ ...sdkConfig,
135
+ ...fixed,
136
+ ...rest,
137
+ cubeSigner: rest.cubeSigner ?? fixed.cubeSigner
138
+ };
139
+ if (registerUser != null && merged.cubeSigner) {
140
+ merged.cubeSigner = {
141
+ ...merged.cubeSigner,
142
+ oidcLoginHooks: {
143
+ ...merged.cubeSigner.oidcLoginHooks,
144
+ registerUser
145
+ }
146
+ };
147
+ }
148
+ sdkConfig = merged;
149
+ tryAutoReconnect().catch(() => {
150
+ });
151
+ }
152
+ function getSDKConfig() {
153
+ return sdkConfig;
154
+ }
155
+
156
+ // src/auth/google.ts
157
+ var GIS_URL = "https://accounts.google.com/gsi/client";
158
+ var loadPromise = null;
159
+ var currentCredentialHandler = null;
160
+ var initializedKey = null;
161
+ function loadGIS() {
162
+ if (loadPromise) return loadPromise;
163
+ if (window.google?.accounts?.id) {
164
+ loadPromise = Promise.resolve();
165
+ return loadPromise;
166
+ }
167
+ loadPromise = new Promise((resolve, reject) => {
168
+ const script = document.createElement("script");
169
+ script.src = GIS_URL;
170
+ script.async = true;
171
+ script.defer = true;
172
+ script.onload = () => resolve();
173
+ script.onerror = () => reject(new Error("Failed to load Google Identity Services"));
174
+ document.head.appendChild(script);
175
+ });
176
+ return loadPromise;
177
+ }
178
+ function decodeJwtPayload(token) {
179
+ const parts = token.split(".");
180
+ if (parts.length !== 3) throw new Error("Invalid JWT");
181
+ const payload = parts[1];
182
+ if (!payload) throw new Error("Invalid JWT payload");
183
+ let padded = payload.replace(/-/g, "+").replace(/_/g, "/");
184
+ while (padded.length % 4 !== 0) padded += "=";
185
+ return JSON.parse(atob(padded));
186
+ }
187
+ function isFedCMSupported() {
188
+ if (typeof window === "undefined" || typeof navigator === "undefined") return false;
189
+ if (!window.isSecureContext) return false;
190
+ return typeof navigator.credentials?.get === "function";
191
+ }
192
+ async function signInWithGoogle(clientId) {
193
+ await loadGIS();
194
+ const gid = window.google?.accounts?.id;
195
+ if (!gid) throw new Error("Google Identity Services not available");
196
+ const SIGN_IN_TIMEOUT_MS = 9e4;
197
+ return new Promise((resolve, reject) => {
198
+ let settled = false;
199
+ let fallbackContainer = null;
200
+ const cleanupFallback = () => {
201
+ if (!fallbackContainer) return;
202
+ fallbackContainer.remove();
203
+ fallbackContainer = null;
204
+ };
205
+ const finish = (fn) => {
206
+ if (settled) return;
207
+ settled = true;
208
+ clearTimeout(timeoutId);
209
+ cleanupFallback();
210
+ fn();
211
+ };
212
+ const timeoutId = setTimeout(() => {
213
+ finish(() => reject(new Error("Google sign-in timed out")));
214
+ }, SIGN_IN_TIMEOUT_MS);
215
+ const handleCredential = (response) => {
216
+ finish(() => {
217
+ try {
218
+ const payload = decodeJwtPayload(response.credential);
219
+ resolve({
220
+ idToken: response.credential,
221
+ email: payload.email,
222
+ name: payload.name,
223
+ picture: payload.picture
224
+ });
225
+ } catch {
226
+ resolve({ idToken: response.credential });
227
+ }
228
+ });
229
+ };
230
+ const useFedcmForPrompt = isFedCMSupported();
231
+ const initKey = `${clientId}\0${useFedcmForPrompt ? "1" : "0"}`;
232
+ currentCredentialHandler = handleCredential;
233
+ if (initializedKey !== initKey) {
234
+ initializedKey = initKey;
235
+ gid.initialize({
236
+ client_id: clientId,
237
+ callback: (response) => currentCredentialHandler?.(response),
238
+ auto_select: false,
239
+ cancel_on_tap_outside: true,
240
+ use_fedcm_for_prompt: useFedcmForPrompt
241
+ });
242
+ }
243
+ const triggerFallback = () => {
244
+ if (settled) return;
245
+ fallbackContainer = document.createElement("div");
246
+ Object.assign(fallbackContainer.style, {
247
+ position: "fixed",
248
+ top: "-9999px",
249
+ left: "-9999px",
250
+ opacity: "0",
251
+ pointerEvents: "none"
252
+ });
253
+ document.body.appendChild(fallbackContainer);
254
+ gid.renderButton(fallbackContainer, { type: "standard", size: "large" });
255
+ const tryClickButton = (attemptsLeft) => {
256
+ requestAnimationFrame(() => {
257
+ const btn = fallbackContainer?.querySelector('[role="button"]') ?? fallbackContainer?.querySelector("div[style]");
258
+ if (btn) {
259
+ Object.assign(fallbackContainer.style, { pointerEvents: "auto" });
260
+ btn.click();
261
+ return;
262
+ }
263
+ if (attemptsLeft > 0) {
264
+ tryClickButton(attemptsLeft - 1);
265
+ return;
266
+ }
267
+ finish(() => reject(new Error("Google sign-in unavailable")));
268
+ });
269
+ };
270
+ tryClickButton(8);
271
+ };
272
+ gid.prompt((moment) => {
273
+ if (settled) return;
274
+ if (moment.isDismissedMoment()) {
275
+ const reason = moment.getDismissedReason();
276
+ if (reason === "credential_returned") return;
277
+ finish(() => reject(new Error(`Google sign-in dismissed: ${reason}`)));
278
+ return;
279
+ }
280
+ if (moment.isSkippedMoment()) {
281
+ triggerFallback();
282
+ return;
283
+ }
284
+ if (moment.isNotDisplayed()) {
285
+ triggerFallback();
286
+ }
287
+ });
288
+ });
289
+ }
290
+
291
+ // src/auth/twitter.ts
292
+ function generateRandom(length) {
293
+ const array = new Uint8Array(length);
294
+ crypto.getRandomValues(array);
295
+ return Array.from(array, (b) => b.toString(16).padStart(2, "0")).join("");
296
+ }
297
+ function base64url(buffer) {
298
+ const bytes = new Uint8Array(buffer);
299
+ let binary = "";
300
+ for (const b of bytes) binary += String.fromCharCode(b);
301
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
302
+ }
303
+ async function createCodeChallenge(verifier) {
304
+ const encoder = new TextEncoder();
305
+ const data = encoder.encode(verifier);
306
+ const digest = await crypto.subtle.digest("SHA-256", data);
307
+ return base64url(digest);
308
+ }
309
+ var POPUP_WIDTH = 600;
310
+ var POPUP_HEIGHT = 700;
311
+ var MESSAGE_TYPE = "twitter-oauth-callback";
312
+ var TWITTER_AUTH_URL = "https://twitter.com/i/oauth2/authorize";
313
+ function notifyTwitterCallback() {
314
+ const params = new URLSearchParams(window.location.search);
315
+ const code = params.get("code");
316
+ const state = params.get("state");
317
+ const error = params.get("error");
318
+ if (window.opener) {
319
+ window.opener.postMessage(
320
+ { type: MESSAGE_TYPE, code, state, error },
321
+ window.location.origin
322
+ );
323
+ window.close();
324
+ }
325
+ }
326
+ async function signInWithTwitter(clientId, redirectUri) {
327
+ const codeVerifier = generateRandom(64);
328
+ const codeChallenge = await createCodeChallenge(codeVerifier);
329
+ const state = generateRandom(16);
330
+ const authUrl = new URL(TWITTER_AUTH_URL);
331
+ authUrl.searchParams.set("response_type", "code");
332
+ authUrl.searchParams.set("client_id", clientId);
333
+ authUrl.searchParams.set("redirect_uri", redirectUri);
334
+ authUrl.searchParams.set("scope", "tweet.read users.read offline.access");
335
+ authUrl.searchParams.set("state", state);
336
+ authUrl.searchParams.set("code_challenge", codeChallenge);
337
+ authUrl.searchParams.set("code_challenge_method", "S256");
338
+ const left = Math.round(screen.width / 2 - POPUP_WIDTH / 2);
339
+ const top = Math.round(screen.height / 2 - POPUP_HEIGHT / 2);
340
+ const popup = window.open(
341
+ authUrl.toString(),
342
+ "twitter-auth",
343
+ `width=${POPUP_WIDTH},height=${POPUP_HEIGHT},left=${left},top=${top},toolbar=no,menubar=no`
344
+ );
345
+ if (!popup) {
346
+ throw new Error("Failed to open Twitter login popup. Check your popup blocker.");
347
+ }
348
+ return new Promise((resolve, reject) => {
349
+ let settled = false;
350
+ const cleanup = () => {
351
+ window.removeEventListener("message", onMessage);
352
+ clearInterval(pollTimer);
353
+ };
354
+ const onMessage = (event) => {
355
+ if (event.origin !== window.location.origin) return;
356
+ const data = event.data;
357
+ if (!data || data.type !== MESSAGE_TYPE) return;
358
+ if (settled) return;
359
+ settled = true;
360
+ cleanup();
361
+ if (data.error) {
362
+ reject(new Error(`Twitter auth error: ${data.error}`));
363
+ return;
364
+ }
365
+ if (!data.code) {
366
+ reject(new Error("No authorization code received from Twitter"));
367
+ return;
368
+ }
369
+ if (data.state !== state) {
370
+ reject(new Error("State mismatch - possible CSRF attack"));
371
+ return;
372
+ }
373
+ resolve({
374
+ code: data.code,
375
+ codeVerifier,
376
+ state
377
+ });
378
+ };
379
+ const pollTimer = setInterval(() => {
380
+ if (popup.closed && !settled) {
381
+ settled = true;
382
+ cleanup();
383
+ reject(new Error("Twitter login popup was closed"));
384
+ }
385
+ }, 500);
386
+ window.addEventListener("message", onMessage);
387
+ });
388
+ }
389
+ function requireSession() {
390
+ const session = sessionStore.getState().session;
391
+ if (!session) throw new Error("Login required");
392
+ return session;
393
+ }
394
+ var createDepositController = (custody, marketData) => {
395
+ let status = { phase: "idle" };
396
+ const notify = (next, cb) => {
397
+ status = next;
398
+ cb?.(status);
399
+ };
400
+ const open = async (config) => {
401
+ const session = requireSession();
402
+ const chain = config?.preferredChain ?? session.chainContext?.settlementChain ?? session.chain ?? "AB_CORE";
403
+ const token = config?.preferredToken || getEnv("FUNDING_TOKEN_SYMBOL") || "USDT";
404
+ try {
405
+ const { address } = await marketData.getDepositAddress(token, chain);
406
+ const depositId = `${chain}:${token}:${Date.now()}`;
407
+ notify({ phase: "address-issued", depositId, address }, config?.onStatusChange);
408
+ notify({ phase: "confirming", depositId }, config?.onStatusChange);
409
+ const { status: finalStatus, txHash } = await custody.getDepositStatus(depositId);
410
+ notify(
411
+ finalStatus === "SETTLED" ? { phase: "settled", depositId, txHash } : { phase: "failed", reason: finalStatus },
412
+ config?.onStatusChange
413
+ );
414
+ } catch (error) {
415
+ notify({ phase: "failed", reason: error.message }, config?.onStatusChange);
416
+ }
417
+ };
418
+ return {
419
+ get status() {
420
+ return status;
421
+ },
422
+ open,
423
+ fetchTokens() {
424
+ requireSession();
425
+ return marketData.getSupportedTokens("deposit");
426
+ },
427
+ fetchChains(token) {
428
+ requireSession();
429
+ return marketData.getSupportedChains(token, "deposit");
430
+ },
431
+ fetchQuote(token, chain, amount) {
432
+ requireSession();
433
+ return marketData.getQuote({ token, chain, amount, direction: "deposit" });
434
+ },
435
+ fetchDepositAddress(token, chain) {
436
+ requireSession();
437
+ return marketData.getDepositAddress(token, chain);
438
+ }
439
+ };
440
+ };
441
+ function requireSession2() {
442
+ const session = sessionStore.getState().session;
443
+ if (!session) throw new Error("Login required");
444
+ return session;
445
+ }
446
+ var createWithdrawController = (custody, marketData) => {
447
+ let status = { phase: "idle" };
448
+ const update = (next, cb) => {
449
+ status = next;
450
+ cb?.(status);
451
+ };
452
+ const open = async (config) => {
453
+ const session = requireSession2();
454
+ const token = config?.defaultToken || getEnv("FUNDING_TOKEN_SYMBOL") || "USDT";
455
+ const chain = config?.defaultChain ?? session.chainContext?.settlementChain ?? session.chain ?? "AB_CORE";
456
+ const targetAddress = config?.targetAddress;
457
+ if (!targetAddress) throw new Error("targetAddress required for withdraw");
458
+ try {
459
+ const { requestId } = await custody.requestWithdraw({
460
+ amount: config?.defaultAmount ?? "0",
461
+ token,
462
+ chain,
463
+ targetAddress
464
+ });
465
+ update({ phase: "requested", requestId }, config?.onStatusChange);
466
+ update({ phase: "processing", requestId }, config?.onStatusChange);
467
+ const { status: finalStatus, txHash } = await custody.getWithdrawStatus(requestId);
468
+ update(
469
+ finalStatus === "SETTLED" ? { phase: "settled", requestId, txHash } : { phase: "failed", reason: finalStatus },
470
+ config?.onStatusChange
471
+ );
472
+ } catch (error) {
473
+ update({ phase: "failed", reason: error.message }, config?.onStatusChange);
474
+ }
475
+ };
476
+ return {
477
+ get status() {
478
+ return status;
479
+ },
480
+ open,
481
+ fetchTokens() {
482
+ requireSession2();
483
+ return marketData.getSupportedTokens("withdraw");
484
+ },
485
+ fetchChains(token) {
486
+ requireSession2();
487
+ return marketData.getSupportedChains(token, "withdraw");
488
+ },
489
+ fetchQuote(token, chain, amount) {
490
+ requireSession2();
491
+ return marketData.getQuote({ token, chain, amount, direction: "withdraw" });
492
+ }
493
+ };
494
+ };
495
+ function createClient() {
496
+ const BASE_URL = getEnv("MERCHANT_BASE_URL");
497
+ if (!BASE_URL) {
498
+ throw new Error("MERCHANT_BASE_URL is not set");
499
+ }
500
+ return axios.create({
501
+ baseURL: BASE_URL,
502
+ timeout: 3e4,
503
+ headers: { "Content-Type": "application/json" }
504
+ });
505
+ }
506
+ function unwrap(res) {
507
+ if (res.code !== 0 || res.data === null) {
508
+ throw new Error(res.msg || "API error");
509
+ }
510
+ return res.data;
511
+ }
512
+ var apiClient = createClient();
513
+ function configureMerchantApi() {
514
+ apiClient = createClient();
515
+ }
516
+ function getMerchantApiClient() {
517
+ return apiClient;
518
+ }
519
+ async function getChains() {
520
+ try {
521
+ const { data } = await apiClient.get("/chains");
522
+ return unwrap(data);
523
+ } catch {
524
+ throw new Error("Failed to get chains");
525
+ }
526
+ }
527
+ async function registerPlatform(body) {
528
+ try {
529
+ const { data } = await apiClient.post(
530
+ "/api/v1/platform",
531
+ body
532
+ );
533
+ return unwrap(data);
534
+ } catch {
535
+ throw new Error("Failed to register platform");
536
+ }
537
+ }
538
+ async function quote(body) {
539
+ const { data } = await apiClient.post("/api/v1/quote", body);
540
+ return unwrap(data);
541
+ }
542
+ async function getDepositOrder(orderId) {
543
+ try {
544
+ const { data } = await apiClient.get(
545
+ `/api/v1/orders/deposit/${encodeURIComponent(orderId)}`
546
+ );
547
+ return unwrap(data);
548
+ } catch {
549
+ throw new Error("Failed to get deposit order");
550
+ }
551
+ }
552
+ async function getWithdrawOrder(orderId) {
553
+ try {
554
+ const { data } = await apiClient.get(
555
+ `/api/v1/orders/withdraw/${encodeURIComponent(orderId)}`
556
+ );
557
+ return unwrap(data);
558
+ } catch {
559
+ throw new Error("Failed to get withdraw order");
560
+ }
561
+ }
562
+ async function createOrder(body) {
563
+ try {
564
+ const { data } = await apiClient.post("/order", body);
565
+ return unwrap(data);
566
+ } catch {
567
+ throw new Error("Failed to create order");
568
+ }
569
+ }
570
+
571
+ // src/modules/marketData.ts
572
+ var cachedChains = null;
573
+ async function fetchChainsFromApi() {
574
+ if (cachedChains) return cachedChains;
575
+ try {
576
+ const { chains } = await getChains();
577
+ if (chains.length > 0) {
578
+ cachedChains = chains;
579
+ return chains;
580
+ }
581
+ return [];
582
+ } catch {
583
+ return [];
584
+ }
585
+ }
586
+ function chainToChainInfo(chain) {
587
+ return {
588
+ id: chain.chain_id,
589
+ name: chain.network
590
+ };
591
+ }
592
+ function findTokenInChains(chains, chainId, tokenSymbol) {
593
+ const chain = chains.find((c) => c.chain_id === chainId);
594
+ return chain?.tokens.find((t) => t.symbol === tokenSymbol);
595
+ }
596
+ function formatMinimumDepositDisplay(token, tokenSymbol) {
597
+ const raw = token.minimum_deposit?.trim();
598
+ if (raw == null || raw === "") return void 0;
599
+ try {
600
+ return `${formatUnits(BigInt(raw), token.decimals)} ${tokenSymbol}`;
601
+ } catch {
602
+ return `${raw} ${tokenSymbol}`;
603
+ }
604
+ }
605
+ function deriveTokensFromChains(chains) {
606
+ const bySymbol = /* @__PURE__ */ new Map();
607
+ for (const chain of chains) {
608
+ for (const t of chain.tokens) {
609
+ if (!bySymbol.has(t.symbol)) {
610
+ bySymbol.set(t.symbol, {
611
+ symbol: t.symbol,
612
+ name: t.symbol,
613
+ decimals: t.decimals
614
+ });
615
+ }
616
+ }
617
+ }
618
+ return Array.from(bySymbol.values());
619
+ }
620
+ function computeDefaultQuote(request) {
621
+ const isStable = ["USDT", "USDC", "USD1"].includes(request.token);
622
+ const slippage = isStable ? "0.3" : "1.0";
623
+ const feeRate = request.direction === "withdraw" ? 1e-3 : 0;
624
+ const amount = Number(request.amount) || 0;
625
+ const fee = (amount * feeRate).toFixed(2);
626
+ const estimatedAmount = (amount - Number(fee)).toFixed(6);
627
+ return {
628
+ quoteId: `quote-${Date.now()}`,
629
+ estimatedAmount: amount > 0 ? estimatedAmount : "0",
630
+ slippage,
631
+ fee,
632
+ feeToken: request.token,
633
+ exchangeRate: "1.0",
634
+ expiresAt: Date.now() + 3e4
635
+ };
636
+ }
637
+ function createMarketDataProvider() {
638
+ return {
639
+ async getSupportedTokens(_direction) {
640
+ const chains = await fetchChainsFromApi();
641
+ const tokens = deriveTokensFromChains(chains);
642
+ return tokens.length > 0 ? tokens : [];
643
+ },
644
+ async getSupportedChains(token, _direction) {
645
+ const chains = await fetchChainsFromApi();
646
+ const forToken = chains.filter((c) => c.tokens.some((t) => t.symbol === token));
647
+ const list = forToken.length > 0 ? forToken : chains;
648
+ return list.map(chainToChainInfo);
649
+ },
650
+ async getQuote(request) {
651
+ return computeDefaultQuote(request);
652
+ },
653
+ async getDepositAddress(token, chain) {
654
+ const session = sessionStore.getState().session;
655
+ const chains = await fetchChainsFromApi();
656
+ const meta = findTokenInChains(chains, chain, token);
657
+ const minimumDeposit = meta != null ? formatMinimumDepositDisplay(meta, token) : void 0;
658
+ return {
659
+ address: session?.address ?? "",
660
+ minimumDeposit
661
+ };
662
+ }
663
+ };
664
+ }
665
+
666
+ // ../wallet-utils/dist/index.js
667
+ var __defProp = Object.defineProperty;
668
+ var __export = (target, all) => {
669
+ for (var name in all)
670
+ __defProp(target, name, { get: all[name], enumerable: true });
671
+ };
672
+ var cache_exports = {};
673
+ __export(cache_exports, {
674
+ clear: () => clear,
675
+ get: () => get,
676
+ remove: () => remove,
677
+ set: () => set,
678
+ setKeyNS: () => setKeyNS
679
+ });
680
+ var keyNS = "tomo-";
681
+ function get(key) {
682
+ if (typeof window === "undefined") {
683
+ return null;
684
+ }
685
+ const tempKey = keyNS + key;
686
+ if (!isKeyExist(tempKey)) {
687
+ return null;
688
+ }
689
+ let val = null;
690
+ try {
691
+ const data = window.localStorage.getItem(tempKey) || window.sessionStorage.getItem(tempKey);
692
+ val = JSON.parse(data);
693
+ } catch (err) {
694
+ console.error(err);
695
+ }
696
+ if (val !== null && Object.prototype.hasOwnProperty.call(val, "type") && Object.prototype.hasOwnProperty.call(val, "data")) {
697
+ return val["data"];
698
+ }
699
+ return null;
700
+ }
701
+ function set(key, val, isTemp) {
702
+ if (typeof window === "undefined") {
703
+ return false;
704
+ }
705
+ let store;
706
+ if (isTemp) {
707
+ store = window.sessionStorage;
708
+ } else {
709
+ store = window.localStorage;
710
+ }
711
+ const data = JSON.stringify({
712
+ data: val,
713
+ time: (/* @__PURE__ */ new Date()).getTime(),
714
+ //for manage by time limit
715
+ type: typeof val
716
+ });
717
+ try {
718
+ store.setItem(keyNS + key, data);
719
+ return true;
720
+ } catch (err) {
721
+ if (err?.name?.toUpperCase().indexOf("QUOTA") >= 0) {
722
+ window.localStorage.clear();
723
+ store.setItem(keyNS + key, data);
724
+ }
725
+ }
726
+ return false;
727
+ }
728
+ function remove(key) {
729
+ if (typeof window === "undefined") {
730
+ return;
731
+ }
732
+ const tempKey = keyNS + key;
733
+ window.localStorage.removeItem(tempKey);
734
+ window.sessionStorage.removeItem(tempKey);
735
+ }
736
+ function clear() {
737
+ if (typeof window === "undefined") {
738
+ return;
739
+ }
740
+ window?.localStorage?.clear();
741
+ window?.sessionStorage?.clear();
742
+ }
743
+ function isKeyExist(key) {
744
+ if (typeof window === "undefined") {
745
+ return false;
746
+ }
747
+ return Object.prototype.hasOwnProperty.call(window.localStorage, key) || Object.prototype.hasOwnProperty.call(window.sessionStorage, key);
748
+ }
749
+ function setKeyNS(NS) {
750
+ const isString = typeof NS === "string";
751
+ if (isString && NS !== "") {
752
+ keyNS = NS;
753
+ }
754
+ }
755
+ function pick2(...candidates) {
756
+ for (const c of candidates) {
757
+ if (c != null && c !== "") return c;
758
+ }
759
+ return void 0;
760
+ }
761
+ function nextPublicProcessEnvKey2(logicalKey) {
762
+ return `NEXT_PUBLIC_${logicalKey}`;
763
+ }
764
+ function readProcessEnvStatic2(key) {
765
+ if (typeof process === "undefined" || !process.env) return void 0;
766
+ switch (key) {
767
+ case "STAGE":
768
+ return pick2(
769
+ process.env.NEXT_PUBLIC_STAGE,
770
+ process.env.STAGE
771
+ );
772
+ case "FUNDING_CHAIN_ID":
773
+ return pick2(
774
+ process.env.NEXT_PUBLIC_FUNDING_CHAIN_ID,
775
+ process.env.FUNDING_CHAIN_ID
776
+ );
777
+ /** Next.js 仅内联「静态」`process.env.NEXT_PUBLIC_*`;动态键名在客户端会为 undefined,必须逐键写出。 */
778
+ case "GOOGLE_CLIENT_ID":
779
+ return pick2(
780
+ process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
781
+ process.env.GOOGLE_CLIENT_ID
782
+ );
783
+ case "X_CLIENT_ID":
784
+ return pick2(
785
+ process.env.NEXT_PUBLIC_X_CLIENT_ID,
786
+ process.env.X_CLIENT_ID
787
+ );
788
+ case "MERCHANT_BASE_URL":
789
+ return pick2(
790
+ process.env.NEXT_PUBLIC_MERCHANT_BASE_URL,
791
+ process.env.MERCHANT_BASE_URL
792
+ );
793
+ case "RELAY_ORIGIN":
794
+ return pick2(
795
+ process.env.NEXT_PUBLIC_RELAY_ORIGIN,
796
+ process.env.RELAY_ORIGIN
797
+ );
798
+ case "CUBE_SIGNER_ENV":
799
+ return pick2(
800
+ process.env.NEXT_PUBLIC_CUBE_SIGNER_ENV,
801
+ process.env.CUBE_SIGNER_ENV
802
+ );
803
+ case "CUBE_SIGNER_ORG_ID":
804
+ return pick2(
805
+ process.env.NEXT_PUBLIC_CUBE_SIGNER_ORG_ID,
806
+ process.env.CUBE_SIGNER_ORG_ID
807
+ );
808
+ case "CUBE_REG":
809
+ return pick2(
810
+ process.env.NEXT_PUBLIC_CUBE_REG,
811
+ process.env.CUBE_REG
812
+ );
813
+ case "FUNDING_TOKEN_SYMBOL":
814
+ return pick2(
815
+ process.env.NEXT_PUBLIC_FUNDING_TOKEN_SYMBOL,
816
+ process.env.FUNDING_TOKEN_SYMBOL
817
+ );
818
+ case "FUNDING_TOKEN_ADDRESS":
819
+ return pick2(
820
+ process.env.NEXT_PUBLIC_FUNDING_TOKEN_ADDRESS,
821
+ process.env.FUNDING_TOKEN_ADDRESS
822
+ );
823
+ default:
824
+ return pick2(
825
+ process.env[`NEXT_PUBLIC_${key}`],
826
+ process.env[key]
827
+ );
828
+ }
829
+ }
830
+ function getEnv2(key) {
831
+ const staticVal = readProcessEnvStatic2(key);
832
+ if (staticVal != null && staticVal !== "") return staticVal;
833
+ const g = globalThis;
834
+ const env = g.process?.env;
835
+ if (env) {
836
+ const pub = nextPublicProcessEnvKey2(key);
837
+ const v = env[key] ?? env[pub];
838
+ if (v != null && v !== "") return v;
839
+ }
840
+ try {
841
+ const m = import.meta.env;
842
+ if (m) {
843
+ const pub = nextPublicProcessEnvKey2(key);
844
+ const v = m[key] ?? m[pub];
845
+ if (v != null && v !== "") return v;
846
+ }
847
+ } catch {
848
+ }
849
+ console.error(`${key} is not set.`);
850
+ return "";
851
+ }
852
+ var TENDERLY_BSC_3131 = {
853
+ chainId: "3131",
854
+ name: "BSC_TENDERLY",
855
+ chainName: "BSC_TENDERLY",
856
+ nativeCurrencyName: "BSC",
857
+ nativeCurrencySymbol: "BSC",
858
+ nativeCurrencyDecimals: 18,
859
+ rpcUrls: [
860
+ "https://virtual.binance.eu.rpc.tenderly.co/e643ea28-32eb-4fb9-8116-90be24f7defa"
861
+ ],
862
+ blockExplorerUrl: "https://dashboard.tenderly.co/explorer/vnet/6593bc72-f548-497d-bff9-5be061436a48",
863
+ platformType: "EVM",
864
+ icon: "https://static.tomo.inc/token/bsc_new.svg",
865
+ // Tenderly 默认资金侧合约地址(测试环境镜像):
866
+ defaultFundingTokenAddress: "0x55d398326f99059fF775485246999027B3197955"
867
+ };
868
+ var BSC_MAINNET_56 = {
869
+ chainId: "56",
870
+ name: "BSC",
871
+ chainName: "BNB Smart Chain",
872
+ nativeCurrencyName: "BNB",
873
+ nativeCurrencySymbol: "BNB",
874
+ nativeCurrencyDecimals: 18,
875
+ rpcUrls: ["https://bsc-dataseed.binance.org", "https://bsc-dataseed1.defibit.io"],
876
+ blockExplorerUrl: "https://bscscan.com",
877
+ platformType: "EVM",
878
+ icon: "https://static.tomo.inc/token/bsc_new.svg",
879
+ // 主网默认资金侧合约地址(USDT);如需覆盖请使用 FUNDING_TOKEN_ADDRESS 环境变量
880
+ defaultFundingTokenAddress: "0x55d398326f99059fF775485246999027B3197955"
881
+ };
882
+ var CHAIN_REGISTRY = {
883
+ [TENDERLY_BSC_3131.chainId]: TENDERLY_BSC_3131,
884
+ [BSC_MAINNET_56.chainId]: BSC_MAINNET_56
885
+ };
886
+ var DEFAULT_FUNDING_CHAIN_ID = getEnv2("FUNDING_CHAIN_ID") || "3131";
887
+ function normalizeFundingChainId(chainId) {
888
+ if (chainId === void 0 || chainId === null) return DEFAULT_FUNDING_CHAIN_ID;
889
+ const s = String(chainId).trim();
890
+ return s === "" ? DEFAULT_FUNDING_CHAIN_ID : s;
891
+ }
892
+ function getChainInfo(chainId) {
893
+ const id = normalizeFundingChainId(chainId);
894
+ const info = CHAIN_REGISTRY[id];
895
+ if (!info) {
896
+ throw new Error(
897
+ `Unsupported funding chainId "${id}". Supported: ${Object.keys(CHAIN_REGISTRY).sort().join(", ")}`
898
+ );
899
+ }
900
+ return info;
901
+ }
902
+ function pickEnvFundingTokenAddress() {
903
+ const tryPairs = [
904
+ ["NEXT_PUBLIC_FUNDING_TOKEN_ADDRESS", "FUNDING_TOKEN_ADDRESS"]
905
+ ];
906
+ if (typeof process !== "undefined" && process.env) {
907
+ for (const [pub, priv] of tryPairs) {
908
+ const a = process.env[pub];
909
+ const b = process.env[priv];
910
+ if (a != null && a !== "") return a;
911
+ if (b != null && b !== "") return b;
912
+ }
913
+ }
914
+ try {
915
+ const m = import.meta.env;
916
+ if (m) {
917
+ for (const [pub, priv] of tryPairs) {
918
+ const a = m[pub];
919
+ const b = m[priv];
920
+ if (a != null && a !== "") return a;
921
+ if (b != null && b !== "") return b;
922
+ }
923
+ }
924
+ } catch {
925
+ }
926
+ return void 0;
927
+ }
928
+ function getFundingTokenAddress(chainId) {
929
+ const v = pickEnvFundingTokenAddress();
930
+ if (v && /^0x[0-9a-fA-F]{40}$/.test(v)) return v;
931
+ return getChainInfo(chainId).defaultFundingTokenAddress;
932
+ }
933
+ var DEFAULT_FUNDING_TOKEN_ADDRESS = getFundingTokenAddress(DEFAULT_FUNDING_CHAIN_ID);
934
+ var ClientIds = {
935
+ google: getEnv2("GOOGLE_CLIENT_ID"),
936
+ x: getEnv2("X_CLIENT_ID")
937
+ };
938
+
939
+ // src/modules/balanceQuery.ts
940
+ var ERC20_BALANCE_OF_SELECTOR = "0x70a08231";
941
+ function padAddress(address) {
942
+ return address.toLowerCase().replace("0x", "").padStart(64, "0");
943
+ }
944
+ function formatUnits2(value, decimals) {
945
+ const divisor = 10n ** BigInt(decimals);
946
+ const intPart = value / divisor;
947
+ const fracPart = value % divisor;
948
+ if (fracPart === 0n) return intPart.toString();
949
+ const fracStr = fracPart.toString().padStart(decimals, "0").replace(/0+$/, "");
950
+ return `${intPart}.${fracStr}`;
951
+ }
952
+ function formatBalanceDisplay(value, decimals) {
953
+ const full = formatUnits2(value, decimals);
954
+ const n = Number(full);
955
+ return Number.isNaN(n) ? full : n.toFixed(2);
956
+ }
957
+ async function fetchErc20Balance(rpcUrl, tokenAddress, walletAddress) {
958
+ const data = `${ERC20_BALANCE_OF_SELECTOR}${padAddress(walletAddress)}`;
959
+ const response = await fetch(rpcUrl, {
960
+ method: "POST",
961
+ headers: { "Content-Type": "application/json" },
962
+ body: JSON.stringify({
963
+ jsonrpc: "2.0",
964
+ id: 1,
965
+ method: "eth_call",
966
+ params: [{ to: tokenAddress, data }, "latest"]
967
+ })
968
+ });
969
+ const json = await response.json();
970
+ if (json.error) throw new Error(json.error.message ?? "RPC error");
971
+ return BigInt(json.result ?? "0x0");
972
+ }
973
+ async function fetchFundingTokenBalance(walletAddress, options) {
974
+ const chain = getChainInfo(options?.chainId);
975
+ const rpcUrl = options?.rpcUrl ?? chain.rpcUrls[0];
976
+ const tokenAddress = options?.tokenAddress ?? getFundingTokenAddress(options?.chainId);
977
+ const decimals = options?.decimals ?? chain.nativeCurrencyDecimals;
978
+ const FUNDING_TOKEN_SYMBOL3 = getEnv("FUNDING_TOKEN_SYMBOL");
979
+ const displaySymbol = options?.displaySymbol ?? (FUNDING_TOKEN_SYMBOL3 || "Funding");
980
+ const raw = await fetchErc20Balance(rpcUrl, tokenAddress, walletAddress);
981
+ return {
982
+ raw,
983
+ formatted: formatBalanceDisplay(raw, decimals),
984
+ symbol: displaySymbol
985
+ };
986
+ }
987
+ var MAX_WITHDRAW_GAS_LIMIT = 500000n;
988
+ var ERC20_TRANSFER_SELECTOR = "0xa9059cbb";
989
+ function padHex256(value) {
990
+ return value.toString(16).padStart(64, "0");
991
+ }
992
+ function padAddress2(address) {
993
+ return address.toLowerCase().replace("0x", "").padStart(64, "0");
994
+ }
995
+ function parseUnits(value, decimals) {
996
+ if (!value || value === "0") return 0n;
997
+ const [intPart = "0", fracPart = ""] = value.split(".");
998
+ const padded = fracPart.padEnd(decimals, "0").slice(0, decimals);
999
+ return BigInt(intPart) * 10n ** BigInt(decimals) + BigInt(padded);
1000
+ }
1001
+ function encodeTransferData(to, amountWei) {
1002
+ return `${ERC20_TRANSFER_SELECTOR}${padAddress2(to)}${padHex256(amountWei)}`;
1003
+ }
1004
+ function isUnsupportedMethodError(error) {
1005
+ const message = error instanceof Error ? error.message : String(error);
1006
+ return /unsupported rpc method|unsupported method|method not found|does not support/i.test(
1007
+ message
1008
+ );
1009
+ }
1010
+ function toHexQuantity(value) {
1011
+ if (typeof value === "string") {
1012
+ if (/^0x[0-9a-fA-F]+$/.test(value)) {
1013
+ return value;
1014
+ }
1015
+ if (/^\d+$/.test(value)) {
1016
+ return toHex(BigInt(value));
1017
+ }
1018
+ }
1019
+ if (typeof value === "number") {
1020
+ return toHex(BigInt(value));
1021
+ }
1022
+ if (typeof value === "bigint") {
1023
+ return toHex(value);
1024
+ }
1025
+ throw new Error(`Invalid EVM quantity: ${String(value)}`);
1026
+ }
1027
+ async function callRpc(rpcUrl, method, params) {
1028
+ const response = await fetch(rpcUrl, {
1029
+ method: "POST",
1030
+ headers: { "Content-Type": "application/json" },
1031
+ body: JSON.stringify({
1032
+ jsonrpc: "2.0",
1033
+ id: Date.now(),
1034
+ method,
1035
+ params
1036
+ })
1037
+ });
1038
+ const json = await response.json();
1039
+ if (!response.ok || json.error) {
1040
+ throw new Error(json.error?.message ?? `${method} failed`);
1041
+ }
1042
+ return json.result;
1043
+ }
1044
+ async function requestHexQuantity(provider, rpcUrl, method, params) {
1045
+ try {
1046
+ const result = await provider.request({ method, params });
1047
+ return toHexQuantity(result);
1048
+ } catch (error) {
1049
+ if (!isUnsupportedMethodError(error)) {
1050
+ throw error;
1051
+ }
1052
+ return toHexQuantity(await callRpc(rpcUrl, method, params));
1053
+ }
1054
+ }
1055
+ async function ensureFundingEvmChain(provider, chainId) {
1056
+ const hex = `0x${chainId.toString(16)}`;
1057
+ try {
1058
+ await provider.request({ method: "wallet_switchEthereumChain", params: [{ chainId: hex }] });
1059
+ } catch {
1060
+ }
1061
+ }
1062
+ function getDstTokenAddress(chains, chainId, tokenSymbol) {
1063
+ const chain = chains.find((c) => c.chain_id === chainId);
1064
+ return chain?.tokens.find((t) => t.symbol === tokenSymbol)?.address;
1065
+ }
1066
+ function createFundingWithdrawExecutor(options) {
1067
+ const fundingChain = getChainInfo(options?.chainId);
1068
+ const chainIdNum = Number(fundingChain.chainId);
1069
+ const rpcUrl = options?.rpcUrl ?? fundingChain.rpcUrls[0];
1070
+ const tokenAddress = options?.tokenAddress ?? getFundingTokenAddress(options?.chainId);
1071
+ const decimals = options?.decimals ?? fundingChain.nativeCurrencyDecimals;
1072
+ const maxAmountWei = options?.maxAmountWei;
1073
+ const fundingLegTokenSymbol = options?.fundingLegTokenSymbol || getEnv("FUNDING_TOKEN_SYMBOL") || "USDT";
1074
+ return async (request) => {
1075
+ const amountWei = parseUnits(request.amount, decimals);
1076
+ const amountWeiStr = amountWei.toString();
1077
+ if (maxAmountWei != null && amountWei > BigInt(maxAmountWei)) {
1078
+ throw new Error("Withdraw amount exceeds the single-transaction limit");
1079
+ }
1080
+ let session = sessionStore.getState().session;
1081
+ if (!session) throw new Error("Login required");
1082
+ let { provider } = session;
1083
+ try {
1084
+ await provider.request({ method: "eth_chainId", params: [] });
1085
+ } catch (err) {
1086
+ const msg = err.message ?? "";
1087
+ if (msg.includes("restored from cache") || msg.includes("Reconnect your wallet")) {
1088
+ const reconnected = await tryAutoReconnect();
1089
+ if (reconnected) {
1090
+ session = reconnected;
1091
+ provider = reconnected.provider;
1092
+ } else {
1093
+ sessionStore.clearSession();
1094
+ throw new Error("Session expired. Please sign in again.");
1095
+ }
1096
+ }
1097
+ }
1098
+ const chainsRes = await getChains();
1099
+ const chains = chainsRes?.chains ?? [];
1100
+ const dstTokenAddress = getDstTokenAddress(chains, request.chain, request.token);
1101
+ if (!dstTokenAddress) {
1102
+ throw new Error(`Unsupported token ${request.token} on chain ${request.chain}`);
1103
+ }
1104
+ const sourceTokenSymbol = fundingLegTokenSymbol;
1105
+ const orderRes = await createOrder({
1106
+ intent_id: `withdraw-${Date.now()}`,
1107
+ order_type: "NATIVE_SWAP",
1108
+ order_payload: {
1109
+ chain_id: fundingChain.chainId,
1110
+ token_address: tokenAddress,
1111
+ token_amount: amountWeiStr,
1112
+ dst_chain_id: request.chain,
1113
+ dst_token_address: dstTokenAddress,
1114
+ recipient: request.toAddress
1115
+ },
1116
+ payment_pairs: [
1117
+ {
1118
+ token_symbol: sourceTokenSymbol,
1119
+ token_amount: amountWeiStr,
1120
+ token_address: tokenAddress,
1121
+ user_address: session.address,
1122
+ chain_id: fundingChain.chainId
1123
+ }
1124
+ ]
1125
+ });
1126
+ const oneTimeAddress = orderRes.payment_sessions?.[0]?.one_time_wallet_address;
1127
+ if (!oneTimeAddress) {
1128
+ throw new Error("Order created but no one-time wallet address returned");
1129
+ }
1130
+ await ensureFundingEvmChain(provider, chainIdNum);
1131
+ const data = encodeTransferData(oneTimeAddress, amountWei);
1132
+ const nonce = await requestHexQuantity(
1133
+ provider,
1134
+ rpcUrl,
1135
+ "eth_getTransactionCount",
1136
+ [session.address, "latest"]
1137
+ );
1138
+ const tx = {
1139
+ from: session.address,
1140
+ to: tokenAddress,
1141
+ value: "0x0",
1142
+ nonce,
1143
+ data,
1144
+ chainId: toHex(chainIdNum)
1145
+ };
1146
+ const estimatedGasHex = await requestHexQuantity(
1147
+ provider,
1148
+ rpcUrl,
1149
+ "eth_estimateGas",
1150
+ [tx]
1151
+ );
1152
+ const estimatedGas = fromHex(estimatedGasHex, "bigint");
1153
+ const gas = toHex(
1154
+ estimatedGas > MAX_WITHDRAW_GAS_LIMIT ? MAX_WITHDRAW_GAS_LIMIT : estimatedGas
1155
+ );
1156
+ const transaction = {
1157
+ ...tx,
1158
+ gas,
1159
+ maxFeePerGas: toHex(parseGwei("5")),
1160
+ maxPriorityFeePerGas: toHex(parseGwei("1"))
1161
+ };
1162
+ let txHash;
1163
+ try {
1164
+ txHash = await provider.request({
1165
+ method: "eth_sendTransaction",
1166
+ params: [transaction]
1167
+ });
1168
+ } catch (error) {
1169
+ if (!isUnsupportedMethodError(error)) {
1170
+ throw error;
1171
+ }
1172
+ const signedTx = await provider.request({
1173
+ method: "eth_signTransaction",
1174
+ params: [transaction]
1175
+ });
1176
+ txHash = await callRpc(rpcUrl, "eth_sendRawTransaction", [signedTx]);
1177
+ }
1178
+ return { txHash, orderId: orderRes.order_id, fundingChainId: fundingChain.chainId };
1179
+ };
1180
+ }
1181
+
1182
+ // src/modules/withdrawDirect.ts
1183
+ function isUsdtWithdrawDirect(chainId, tokenAddress, chains) {
1184
+ if (chainId !== String(DEFAULT_FUNDING_CHAIN_ID)) return false;
1185
+ const addr = tokenAddress.trim();
1186
+ if (!addr) return false;
1187
+ const chain = chains.find((c) => c.chain_id === chainId);
1188
+ const token = chain?.tokens.find((t) => t.address.toLowerCase() === addr.toLowerCase());
1189
+ return token?.is_usd_stable === true;
1190
+ }
1191
+ function findTokenDataFromChains(chains, chainId, opts) {
1192
+ const chain = chains.find((c) => c.chain_id === chainId);
1193
+ if (!chain?.tokens.length) return void 0;
1194
+ const sym = opts.symbol.trim();
1195
+ const addr = opts.tokenAddress?.trim().toLowerCase();
1196
+ return chain.tokens.find((t) => {
1197
+ if (addr && t.address.toLowerCase() === addr) return true;
1198
+ if (sym.length > 0 && t.symbol === sym) return true;
1199
+ return false;
1200
+ });
1201
+ }
1202
+ var createPolicy = (overrides, options) => createSessionCapabilityPolicy({
1203
+ appId: options?.appId,
1204
+ origin: options?.origin,
1205
+ expiresAt: options?.expiresAt,
1206
+ ...overrides
1207
+ });
1208
+ var withActionMetadata = (action, policy) => ({
1209
+ ...policy,
1210
+ metadata: {
1211
+ ...policy.metadata ?? {},
1212
+ action
1213
+ }
1214
+ });
1215
+ var createPredicateMarketPolicyAdapter = (options) => ({
1216
+ deposit(token, chain, maxAmount) {
1217
+ return withActionMetadata(
1218
+ "deposit",
1219
+ createPolicy(
1220
+ {
1221
+ methods: ["eth_sendTransaction"],
1222
+ chains: [chain],
1223
+ tokens: [token],
1224
+ maxAmount
1225
+ },
1226
+ options
1227
+ )
1228
+ );
1229
+ },
1230
+ withdraw(token, chain, maxAmount) {
1231
+ return withActionMetadata(
1232
+ "withdraw",
1233
+ createPolicy(
1234
+ {
1235
+ methods: ["eth_sendTransaction"],
1236
+ chains: [chain],
1237
+ tokens: [token],
1238
+ maxAmount
1239
+ },
1240
+ options
1241
+ )
1242
+ );
1243
+ },
1244
+ trade(chain, capabilities = ["eth_sendTransaction"]) {
1245
+ return withActionMetadata(
1246
+ "trade",
1247
+ createPolicy(
1248
+ {
1249
+ methods: capabilities,
1250
+ chains: [chain]
1251
+ },
1252
+ options
1253
+ )
1254
+ );
1255
+ }
1256
+ });
1257
+ var cubistCapabilities = [
1258
+ "eth_accounts",
1259
+ "eth_requestAccounts",
1260
+ "eth_chainId",
1261
+ "eth_signTransaction",
1262
+ "personal_sign",
1263
+ "eth_signTypedData_v4",
1264
+ "wallet_disconnect"
1265
+ ];
1266
+ var evmChainIdMap = {
1267
+ ETH: 1,
1268
+ BSC: 56
1269
+ };
1270
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1271
+ var toBigIntQuantity = (value) => {
1272
+ if (typeof value === "bigint") return value;
1273
+ if (typeof value === "number") {
1274
+ if (!Number.isInteger(value) || value < 0) {
1275
+ throw new Error(`Invalid EVM quantity number: ${value}`);
1276
+ }
1277
+ return BigInt(value);
1278
+ }
1279
+ const trimmed = value.trim();
1280
+ if (!trimmed) {
1281
+ throw new Error("EVM quantity cannot be empty");
1282
+ }
1283
+ if (/^0x[0-9a-fA-F]+$/.test(trimmed) || /^\d+$/.test(trimmed)) {
1284
+ return BigInt(trimmed);
1285
+ }
1286
+ throw new Error(`Invalid EVM quantity string: ${value}`);
1287
+ };
1288
+ var toHexQuantity2 = (value) => {
1289
+ if (value === void 0) return void 0;
1290
+ return `0x${toBigIntQuantity(value).toString(16)}`;
1291
+ };
1292
+ var normalizeAccessList = (accessList) => {
1293
+ if (!accessList) return void 0;
1294
+ return accessList.map((item) => ({
1295
+ address: item.address,
1296
+ storageKeys: item.storageKeys
1297
+ }));
1298
+ };
1299
+ var textEncoder = new TextEncoder();
1300
+ var resolveTransactionType = (transaction) => {
1301
+ if (transaction.type !== void 0) {
1302
+ const normalized = toHexQuantity2(transaction.type);
1303
+ if (normalized === "0x0" || normalized === "0x1" || normalized === "0x2") {
1304
+ return normalized;
1305
+ }
1306
+ throw new Error(`Unsupported EVM transaction type for Cubist: ${normalized}`);
1307
+ }
1308
+ if (transaction.maxFeePerGas !== void 0 || transaction.maxPriorityFeePerGas !== void 0) {
1309
+ return "0x2";
1310
+ }
1311
+ if (transaction.accessList?.length) {
1312
+ return "0x1";
1313
+ }
1314
+ return "0x0";
1315
+ };
1316
+ var toCubistSignRequest = (address, chain, transaction) => {
1317
+ const resolvedChainId = (transaction.chainId !== void 0 ? Number(toBigIntQuantity(transaction.chainId)) : void 0) ?? evmChainIdMap[chain];
1318
+ if (!resolvedChainId) {
1319
+ throw new Error("Cubist signing requires an EVM chainId");
1320
+ }
1321
+ const type = resolveTransactionType(transaction);
1322
+ const commonFields = {
1323
+ from: transaction.from ?? address,
1324
+ to: transaction.to,
1325
+ data: transaction.data,
1326
+ gas: toHexQuantity2(transaction.gas),
1327
+ nonce: toHexQuantity2(transaction.nonce),
1328
+ value: toHexQuantity2(transaction.value)
1329
+ };
1330
+ const accessList = normalizeAccessList(transaction.accessList);
1331
+ const tx = type === "0x2" ? {
1332
+ ...commonFields,
1333
+ type,
1334
+ ...accessList ? { accessList } : {},
1335
+ maxFeePerGas: toHexQuantity2(transaction.maxFeePerGas),
1336
+ maxPriorityFeePerGas: toHexQuantity2(transaction.maxPriorityFeePerGas)
1337
+ } : type === "0x1" ? {
1338
+ ...commonFields,
1339
+ type,
1340
+ ...accessList ? { accessList } : {},
1341
+ gasPrice: toHexQuantity2(transaction.gasPrice)
1342
+ } : {
1343
+ ...commonFields,
1344
+ type,
1345
+ gasPrice: toHexQuantity2(transaction.gasPrice)
1346
+ };
1347
+ return {
1348
+ chain_id: resolvedChainId,
1349
+ tx
1350
+ };
1351
+ };
1352
+ var getTransactionParam = (params) => {
1353
+ const candidate = params?.[0];
1354
+ if (!isRecord(candidate)) {
1355
+ throw new Error("eth_signTransaction requires a transaction object");
1356
+ }
1357
+ return candidate;
1358
+ };
1359
+ var toHexBytes = (value) => {
1360
+ if (/^0x[0-9a-fA-F]*$/.test(value)) return value;
1361
+ return `0x${Array.from(textEncoder.encode(value)).map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
1362
+ };
1363
+ var getMessageParam = (address, params) => {
1364
+ const [first, second] = params ?? [];
1365
+ if (typeof second === "string" && second.toLowerCase() === address.toLowerCase()) {
1366
+ return String(first ?? "");
1367
+ }
1368
+ if (typeof first === "string" && first.toLowerCase() === address.toLowerCase()) {
1369
+ return String(second ?? "");
1370
+ }
1371
+ return String(first ?? "");
1372
+ };
1373
+ var getTypedDataParam = (address, params) => {
1374
+ const [first, second] = params ?? [];
1375
+ if (typeof first === "string" && first.toLowerCase() === address.toLowerCase()) {
1376
+ return typeof second === "string" ? JSON.parse(second) : second ?? {};
1377
+ }
1378
+ return typeof second === "string" ? JSON.parse(second) : second ?? first ?? {};
1379
+ };
1380
+ function createEmbeddedProvider({
1381
+ session,
1382
+ address,
1383
+ chain
1384
+ }) {
1385
+ const signer = new EvmSigner(address, session.client);
1386
+ return {
1387
+ async request(payload) {
1388
+ switch (payload.method) {
1389
+ case "eth_accounts":
1390
+ case "eth_requestAccounts":
1391
+ return [address];
1392
+ case "eth_chainId": {
1393
+ const chainId = evmChainIdMap[chain];
1394
+ return `0x${chainId.toString(16)}`;
1395
+ }
1396
+ case "eth_signTransaction": {
1397
+ const transaction = getTransactionParam(payload.params);
1398
+ const signRequest = toCubistSignRequest(address, chain, transaction);
1399
+ return await signer.signTransaction(signRequest);
1400
+ }
1401
+ case "personal_sign": {
1402
+ const message = getMessageParam(address, payload.params);
1403
+ return await signer.signEip191({ data: toHexBytes(message) });
1404
+ }
1405
+ case "eth_signTypedData_v4": {
1406
+ const typedData = getTypedDataParam(address, payload.params);
1407
+ const domain = typedData.domain;
1408
+ const chainId = domain?.chainId !== void 0 ? Number(toBigIntQuantity(domain.chainId)) : evmChainIdMap[chain];
1409
+ if (!chainId) {
1410
+ throw new Error("CubistProvider: typed data signing requires an EVM chainId");
1411
+ }
1412
+ return await signer.signEip712({
1413
+ chain_id: chainId,
1414
+ typed_data: typedData
1415
+ });
1416
+ }
1417
+ default:
1418
+ throw new Error(`CubistProvider: unsupported RPC method "${payload.method}"`);
1419
+ }
1420
+ },
1421
+ async disconnect() {
1422
+ await session.client.revokeSession();
1423
+ }
1424
+ };
1425
+ }
1426
+ var EmbeddedWalletAccountProvider = class {
1427
+ constructor(provider) {
1428
+ this.provider = provider;
1429
+ }
1430
+ async request(payload) {
1431
+ return this.provider.request(payload);
1432
+ }
1433
+ async disconnect() {
1434
+ await this.provider.disconnect();
1435
+ }
1436
+ async eth_accounts() {
1437
+ return this.request({ method: "eth_accounts" });
1438
+ }
1439
+ async eth_chainId() {
1440
+ return this.request({ method: "eth_chainId" });
1441
+ }
1442
+ };
1443
+ var _WalletAccount = class _WalletAccount {
1444
+ static clearInstance() {
1445
+ _WalletAccount.instance = null;
1446
+ _WalletAccount.instanceToken = null;
1447
+ _WalletAccount.walletSession = null;
1448
+ _WalletAccount.cubeSignerSession = null;
1449
+ }
1450
+ static getWalletSession() {
1451
+ return _WalletAccount.walletSession;
1452
+ }
1453
+ static getCubeSignerSession() {
1454
+ return _WalletAccount.cubeSignerSession;
1455
+ }
1456
+ static async getInstance(oidcToken, authSource, cubeSignerConfig) {
1457
+ if (_WalletAccount.instance && _WalletAccount.instanceToken === oidcToken) {
1458
+ return _WalletAccount.instance;
1459
+ }
1460
+ _WalletAccount.clearInstance();
1461
+ const auth = new CubeSignerAuth(cubeSignerConfig);
1462
+ const cubeSignerSession = await auth.loginWithGoogle(oidcToken);
1463
+ const keys = await cubeSignerSession.client.sessionKeys();
1464
+ const evmKey = keys.find((key) => key.cached.key_type === "SecpEthAddr");
1465
+ if (!evmKey) {
1466
+ throw new Error("No EVM key found in CubeSigner session");
1467
+ }
1468
+ const address = evmKey.materialId;
1469
+ const chain = "BSC";
1470
+ const provider = createEmbeddedProvider({
1471
+ session: cubeSignerSession,
1472
+ address,
1473
+ chain
1474
+ });
1475
+ const wrappedProvider = new EmbeddedWalletAccountProvider(provider);
1476
+ const capabilityPolicy = auth.defaultSessionPolicy ? createSessionCapabilityPolicy(auth.defaultSessionPolicy) : void 0;
1477
+ _WalletAccount.instance = wrappedProvider;
1478
+ _WalletAccount.instanceToken = oidcToken;
1479
+ _WalletAccount.cubeSignerSession = cubeSignerSession;
1480
+ _WalletAccount.walletSession = {
1481
+ address,
1482
+ chain,
1483
+ provider: wrappedProvider,
1484
+ walletType: "social",
1485
+ authSource,
1486
+ sessionId: `${authSource}:${address.toLowerCase()}`,
1487
+ expiresAt: capabilityPolicy?.expiresAt,
1488
+ capabilities: [...cubistCapabilities],
1489
+ sessionData: cubeSignerSession.sessionData,
1490
+ chainContext: createChainContext(chain),
1491
+ capabilityPolicy
1492
+ };
1493
+ return wrappedProvider;
1494
+ }
1495
+ };
1496
+ _WalletAccount.instance = null;
1497
+ _WalletAccount.instanceToken = null;
1498
+ _WalletAccount.walletSession = null;
1499
+ _WalletAccount.cubeSignerSession = null;
1500
+ var WalletAccount = _WalletAccount;
1501
+ function clearSocialAccountInstance() {
1502
+ WalletAccount.clearInstance();
1503
+ }
1504
+
1505
+ // src/ui/theme.ts
1506
+ var colors = {
1507
+ background: "#050608",
1508
+ card: "#121214",
1509
+ cardRaised: "#151821",
1510
+ border: "rgba(126,135,162,0.2)",
1511
+ borderStrong: "rgba(255,255,255,0.16)",
1512
+ borderFocused: "#FFFFFF",
1513
+ textPrimary: "#FFFFFF",
1514
+ textSecondary: "#737477",
1515
+ accent: "#29FF9B",
1516
+ accentStrong: "#4AD481",
1517
+ warning: "#FFB547",
1518
+ danger: "#FF6B6B",
1519
+ stepActive: "#FFFFFF",
1520
+ stepInactive: "#36383D",
1521
+ buttonDisabledBg: "rgba(255,255,255,0.14)",
1522
+ buttonDisabledBorder: "#444444"
1523
+ };
1524
+ var radii = {
1525
+ xl: "28px",
1526
+ lg: "20px",
1527
+ pill: "99px",
1528
+ full: "9999px",
1529
+ card: "12px",
1530
+ input: "8px"
1531
+ };
1532
+ var fonts = {
1533
+ family: '"Switzer", "Inter", "SF Pro Display", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
1534
+ };
1535
+ var GoogleIcon = () => /* @__PURE__ */ jsxs("svg", { width: "21", height: "21", viewBox: "0 0 21 21", fill: "none", children: [
1536
+ /* @__PURE__ */ jsx("path", { d: "M20.3 10.73c0-.79-.07-1.54-.19-2.27H10.5v4.51h5.5a4.69 4.69 0 0 1-2.04 3.09v2.57h3.3c1.93-1.78 3.04-4.4 3.04-7.9Z", fill: "#4285F4" }),
1537
+ /* @__PURE__ */ jsx("path", { d: "M10.5 21c2.76 0 5.07-.91 6.76-2.47l-3.3-2.57c-.92.61-2.09.97-3.46.97-2.66 0-4.91-1.8-5.71-4.22H1.39v2.65A10.5 10.5 0 0 0 10.5 21Z", fill: "#34A853" }),
1538
+ /* @__PURE__ */ jsx("path", { d: "M4.79 12.71A6.3 6.3 0 0 1 4.46 10.5c0-.77.13-1.51.33-2.21V5.64H1.39A10.5 10.5 0 0 0 0 10.5c0 1.7.41 3.3 1.39 4.86l3.4-2.65Z", fill: "#FBBC05" }),
1539
+ /* @__PURE__ */ jsx("path", { d: "M10.5 4.07c1.5 0 2.84.51 3.9 1.52l2.92-2.92C15.56 1.02 13.26 0 10.5 0A10.5 10.5 0 0 0 1.39 5.64l3.4 2.65C5.59 5.87 7.84 4.07 10.5 4.07Z", fill: "#EA4335" })
1540
+ ] });
1541
+ var XIcon = () => /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231 5.45-6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117L17.083 19.77Z", fill: "white" }) });
1542
+ var ExpandIcon = ({ expanded }) => /* @__PURE__ */ jsxs(
1543
+ "svg",
1544
+ {
1545
+ width: "24",
1546
+ height: "24",
1547
+ viewBox: "0 0 24 24",
1548
+ fill: "none",
1549
+ style: { transform: expanded ? "rotate(180deg)" : void 0, transition: "transform 0.2s" },
1550
+ children: [
1551
+ /* @__PURE__ */ jsx("path", { d: "M5 9L9 13L13 9", stroke: colors.textSecondary, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
1552
+ /* @__PURE__ */ jsx("path", { d: "M11 9L15 13L19 9", stroke: colors.textSecondary, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
1553
+ ]
1554
+ }
1555
+ );
1556
+ var SpinnerIcon = () => /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", style: { animation: "spin 1s linear infinite" }, children: [
1557
+ /* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "8", stroke: "rgba(255,255,255,0.2)", strokeWidth: "2.5" }),
1558
+ /* @__PURE__ */ jsx("path", { d: "M10 2a8 8 0 0 1 8 8", stroke: colors.textPrimary, strokeWidth: "2.5", strokeLinecap: "round" }),
1559
+ /* @__PURE__ */ jsx("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
1560
+ ] });
1561
+ var defaultSocialProviders = [
1562
+ { id: "google", label: "Continue with Google", icon: /* @__PURE__ */ jsx(GoogleIcon, {}) },
1563
+ { id: "x", label: "Continue with X", icon: /* @__PURE__ */ jsx(XIcon, {}) }
1564
+ ];
1565
+ function resolveWalletItems(wallets, defaultWalletRegistry) {
1566
+ const walletMap = new Map(
1567
+ defaultWalletRegistry.map((item) => [
1568
+ item.id,
1569
+ {
1570
+ name: item.title,
1571
+ installed: item.installed,
1572
+ installUrl: item.installUrl
1573
+ }
1574
+ ])
1575
+ );
1576
+ if (wallets === void 0) {
1577
+ return defaultWalletRegistry.map((item) => ({
1578
+ id: item.id,
1579
+ name: item.title,
1580
+ icon: void 0,
1581
+ installed: item.installed,
1582
+ installUrl: item.installUrl
1583
+ }));
1584
+ }
1585
+ if (wallets.length === 0) {
1586
+ return [];
1587
+ }
1588
+ return wallets.map((wallet) => {
1589
+ const fallback = walletMap.get(wallet.id);
1590
+ return {
1591
+ ...wallet,
1592
+ name: wallet.name ?? fallback?.name ?? wallet.id,
1593
+ installed: wallet.installed ?? fallback?.installed,
1594
+ installUrl: wallet.installUrl ?? fallback?.installUrl
1595
+ };
1596
+ });
1597
+ }
1598
+ function resolveSocialProviders(socialProviders) {
1599
+ if (socialProviders === void 0) {
1600
+ return defaultSocialProviders;
1601
+ }
1602
+ if (socialProviders.length === 0) {
1603
+ return [];
1604
+ }
1605
+ const defaultProviderMap = new Map(
1606
+ defaultSocialProviders.map((provider) => [provider.id, provider])
1607
+ );
1608
+ return socialProviders.map((provider) => {
1609
+ const fallback = defaultProviderMap.get(provider.id);
1610
+ return {
1611
+ ...provider,
1612
+ label: provider.label ?? fallback?.label ?? provider.id,
1613
+ icon: provider.icon ?? fallback?.icon
1614
+ };
1615
+ });
1616
+ }
1617
+ var IconFrame = ({
1618
+ background,
1619
+ children
1620
+ }) => /* @__PURE__ */ jsx(
1621
+ "div",
1622
+ {
1623
+ style: {
1624
+ width: 48,
1625
+ height: 48,
1626
+ borderRadius: 12,
1627
+ background,
1628
+ display: "flex",
1629
+ alignItems: "center",
1630
+ justifyContent: "center",
1631
+ overflow: "hidden"
1632
+ },
1633
+ children
1634
+ }
1635
+ );
1636
+ var MetaMaskWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "#1A0F07", children: /* @__PURE__ */ jsxs("svg", { width: "32", height: "32", viewBox: "0 0 32 32", fill: "none", children: [
1637
+ /* @__PURE__ */ jsx("path", { d: "M8 6L15 11L12 14L8 6Z", fill: "#E17726" }),
1638
+ /* @__PURE__ */ jsx("path", { d: "M24 6L17 11L20 14L24 6Z", fill: "#E27625" }),
1639
+ /* @__PURE__ */ jsx("path", { d: "M11 19L15 22V17L11 19Z", fill: "#F6851B" }),
1640
+ /* @__PURE__ */ jsx("path", { d: "M21 19L17 22V17L21 19Z", fill: "#F6851B" }),
1641
+ /* @__PURE__ */ jsx("path", { d: "M12 14L15 11V17L11 19L12 14Z", fill: "#763D16" }),
1642
+ /* @__PURE__ */ jsx("path", { d: "M20 14L17 11V17L21 19L20 14Z", fill: "#763D16" })
1643
+ ] }) });
1644
+ var OKXWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "#FFFFFF", children: /* @__PURE__ */ jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [
1645
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "2", width: "8", height: "8", rx: "2", fill: "#050608" }),
1646
+ /* @__PURE__ */ jsx("rect", { x: "11", y: "2", width: "8", height: "8", rx: "2", fill: "#050608" }),
1647
+ /* @__PURE__ */ jsx("rect", { x: "20", y: "2", width: "8", height: "8", rx: "2", fill: "#050608" }),
1648
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "11", width: "8", height: "8", rx: "2", fill: "#050608" }),
1649
+ /* @__PURE__ */ jsx("rect", { x: "20", y: "11", width: "8", height: "8", rx: "2", fill: "#050608" }),
1650
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "20", width: "8", height: "8", rx: "2", fill: "#050608" }),
1651
+ /* @__PURE__ */ jsx("rect", { x: "11", y: "20", width: "8", height: "8", rx: "2", fill: "#050608" }),
1652
+ /* @__PURE__ */ jsx("rect", { x: "20", y: "20", width: "8", height: "8", rx: "2", fill: "#050608" })
1653
+ ] }) });
1654
+ var CoinbaseWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "#0052FF", children: /* @__PURE__ */ jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [
1655
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "15", r: "10", stroke: "white", strokeWidth: "4" }),
1656
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "13", width: "12", height: "4", rx: "2", fill: "white" })
1657
+ ] }) });
1658
+ var TrustWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "#3375FF", children: /* @__PURE__ */ jsxs("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", children: [
1659
+ /* @__PURE__ */ jsx("path", { d: "M14 4L21 6.6V12.8C21 17.1 18.1 20.9 14 22.4C9.9 20.9 7 17.1 7 12.8V6.6L14 4Z", fill: "white" }),
1660
+ /* @__PURE__ */ jsx("path", { d: "M14 8L17 9.1V12.3C17 14.7 15.7 16.8 14 17.6C12.3 16.8 11 14.7 11 12.3V9.1L14 8Z", fill: "#3375FF" })
1661
+ ] }) });
1662
+ var PhantomWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "linear-gradient(135deg, #6C47FF 0%, #9B6BFF 100%)", children: /* @__PURE__ */ jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [
1663
+ /* @__PURE__ */ jsx("path", { d: "M8 18.5C8 14.4 11.2 11 15.3 11H20.4C21.8 11 23 12.2 23 13.6C23 15 21.8 16.2 20.4 16.2H14.7", stroke: "white", strokeWidth: "3", strokeLinecap: "round" }),
1664
+ /* @__PURE__ */ jsx("path", { d: "M10.5 14H19.5", stroke: "white", strokeWidth: "3", strokeLinecap: "round" }),
1665
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "20", r: "1.4", fill: "white" }),
1666
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "20", r: "1.4", fill: "white" })
1667
+ ] }) });
1668
+ var RabbyWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "#EBF2FF", children: /* @__PURE__ */ jsxs("svg", { width: "30", height: "30", viewBox: "0 0 30 30", fill: "none", children: [
1669
+ /* @__PURE__ */ jsx("path", { d: "M11 7L13.5 13", stroke: "#7084FF", strokeWidth: "3", strokeLinecap: "round" }),
1670
+ /* @__PURE__ */ jsx("path", { d: "M19 7L16.5 13", stroke: "#7084FF", strokeWidth: "3", strokeLinecap: "round" }),
1671
+ /* @__PURE__ */ jsx("rect", { x: "8", y: "12", width: "14", height: "11", rx: "6", fill: "#7084FF" }),
1672
+ /* @__PURE__ */ jsx("circle", { cx: "13", cy: "17", r: "1.4", fill: "white" }),
1673
+ /* @__PURE__ */ jsx("circle", { cx: "17", cy: "17", r: "1.4", fill: "white" }),
1674
+ /* @__PURE__ */ jsx("path", { d: "M13 20C13.6 20.4 14.3 20.6 15 20.6C15.7 20.6 16.4 20.4 17 20", stroke: "white", strokeWidth: "1.8", strokeLinecap: "round" })
1675
+ ] }) });
1676
+ var RainbowWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "linear-gradient(180deg, #174299 0%, #001E59 100%)", children: /* @__PURE__ */ jsxs("svg", { width: "32", height: "32", viewBox: "0 0 120 120", fill: "none", style: { overflow: "hidden", borderRadius: 12 }, children: [
1677
+ /* @__PURE__ */ jsxs("defs", { children: [
1678
+ /* @__PURE__ */ jsxs("radialGradient", { id: "rainbow_r1", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(26 94) rotate(-90) scale(74)", children: [
1679
+ /* @__PURE__ */ jsx("stop", { offset: "0.770277", stopColor: "#FF4000" }),
1680
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#8754C9" })
1681
+ ] }),
1682
+ /* @__PURE__ */ jsxs("linearGradient", { id: "rainbow_l2", x1: "83", y1: "97", x2: "100", y2: "97", gradientUnits: "userSpaceOnUse", children: [
1683
+ /* @__PURE__ */ jsx("stop", { stopColor: "#FF4000" }),
1684
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#8754C9" })
1685
+ ] }),
1686
+ /* @__PURE__ */ jsxs("linearGradient", { id: "rainbow_l3", x1: "23", y1: "20", x2: "23", y2: "37", gradientUnits: "userSpaceOnUse", children: [
1687
+ /* @__PURE__ */ jsx("stop", { stopColor: "#8754C9" }),
1688
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#FF4000" })
1689
+ ] }),
1690
+ /* @__PURE__ */ jsxs("radialGradient", { id: "rainbow_r4", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(26 94) rotate(-90) scale(58)", children: [
1691
+ /* @__PURE__ */ jsx("stop", { offset: "0.723929", stopColor: "#FFF700" }),
1692
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#FF9901" })
1693
+ ] }),
1694
+ /* @__PURE__ */ jsxs("linearGradient", { id: "rainbow_l5", x1: "68", y1: "97", x2: "84", y2: "97", gradientUnits: "userSpaceOnUse", children: [
1695
+ /* @__PURE__ */ jsx("stop", { stopColor: "#FFF700" }),
1696
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#FF9901" })
1697
+ ] }),
1698
+ /* @__PURE__ */ jsxs("linearGradient", { id: "rainbow_l6", x1: "23", y1: "52", x2: "23", y2: "36", gradientUnits: "userSpaceOnUse", children: [
1699
+ /* @__PURE__ */ jsx("stop", { stopColor: "#FFF700" }),
1700
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#FF9901" })
1701
+ ] }),
1702
+ /* @__PURE__ */ jsxs("radialGradient", { id: "rainbow_r7", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(26 94) rotate(-90) scale(42)", children: [
1703
+ /* @__PURE__ */ jsx("stop", { offset: "0.59513", stopColor: "#00AAFF" }),
1704
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#01DA40" })
1705
+ ] }),
1706
+ /* @__PURE__ */ jsxs("radialGradient", { id: "rainbow_r8", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(51 97) scale(17 45.3333)", children: [
1707
+ /* @__PURE__ */ jsx("stop", { stopColor: "#00AAFF" }),
1708
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#01DA40" })
1709
+ ] }),
1710
+ /* @__PURE__ */ jsxs("radialGradient", { id: "rainbow_r9", cx: "0", cy: "0", r: "1", gradientUnits: "userSpaceOnUse", gradientTransform: "translate(23 69) rotate(-90) scale(17 322.37)", children: [
1711
+ /* @__PURE__ */ jsx("stop", { stopColor: "#00AAFF" }),
1712
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#01DA40" })
1713
+ ] })
1714
+ ] }),
1715
+ /* @__PURE__ */ jsx("path", { d: "M20 38H26C56.9279 38 82 63.0721 82 94V100H94C97.3137 100 100 97.3137 100 94C100 53.1309 66.8691 20 26 20C22.6863 20 20 22.6863 20 26V38Z", fill: "url(#rainbow_r1)" }),
1716
+ /* @__PURE__ */ jsx("path", { d: "M84 94H100C100 97.3137 97.3137 100 94 100H84V94Z", fill: "url(#rainbow_l2)" }),
1717
+ /* @__PURE__ */ jsx("path", { d: "M26 20L26 36H20L20 26C20 22.6863 22.6863 20 26 20Z", fill: "url(#rainbow_l3)" }),
1718
+ /* @__PURE__ */ jsx("path", { d: "M20 36H26C58.0325 36 84 61.9675 84 94V100H66V94C66 71.9086 48.0914 54 26 54H20V36Z", fill: "url(#rainbow_r4)" }),
1719
+ /* @__PURE__ */ jsx("path", { d: "M68 94H84V100H68V94Z", fill: "url(#rainbow_l5)" }),
1720
+ /* @__PURE__ */ jsx("path", { d: "M20 52L20 36L26 36L26 52H20Z", fill: "url(#rainbow_l6)" }),
1721
+ /* @__PURE__ */ jsx("path", { d: "M20 62C20 65.3137 22.6863 68 26 68C40.3594 68 52 79.6406 52 94C52 97.3137 54.6863 100 58 100H68V94C68 70.804 49.196 52 26 52H20V62Z", fill: "url(#rainbow_r7)" }),
1722
+ /* @__PURE__ */ jsx("path", { d: "M52 94H68V100H58C54.6863 100 52 97.3137 52 94Z", fill: "url(#rainbow_r8)" }),
1723
+ /* @__PURE__ */ jsx("path", { d: "M26 68C22.6863 68 20 65.3137 20 62L20 52L26 52L26 68Z", fill: "url(#rainbow_r9)" })
1724
+ ] }) });
1725
+ var ZerionWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "#2962EF", children: /* @__PURE__ */ jsx("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", children: /* @__PURE__ */ jsx("path", { fill: "#fff", d: "M6.073 7c-.48 0-.665.593-.262.841l10.073 6.074a.577.577 0 0 0 .758-.139l4.43-5.814c.3-.404-.004-.962-.525-.962H6.073ZM21.904 21c.48 0 .67-.596.267-.844l-10.075-6.073a.569.569 0 0 0-.751.146l-4.437 5.813c-.301.404.012.958.534.958h14.462Z" }) }) });
1726
+ var BraveWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "#FFF", children: /* @__PURE__ */ jsxs("svg", { width: "32", height: "32", viewBox: "-100 -100 2970 2970", fill: "none", style: { overflow: "hidden", borderRadius: 12 }, children: [
1727
+ /* @__PURE__ */ jsxs("defs", { children: [
1728
+ /* @__PURE__ */ jsxs("linearGradient", { id: "brave_a", y1: "51%", y2: "51%", children: [
1729
+ /* @__PURE__ */ jsx("stop", { offset: "0.4", stopColor: "#f50" }),
1730
+ /* @__PURE__ */ jsx("stop", { offset: "0.6", stopColor: "#ff2000" })
1731
+ ] }),
1732
+ /* @__PURE__ */ jsxs("linearGradient", { id: "brave_b", x1: "2%", y1: "51%", x2: "51%", y2: "51%", children: [
1733
+ /* @__PURE__ */ jsx("stop", { offset: "0", stopColor: "#ff452a" }),
1734
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#ff2000" })
1735
+ ] })
1736
+ ] }),
1737
+ /* @__PURE__ */ jsx("path", { fill: "url(#brave_a)", d: "m2395 723 60-147-170-176c-92-92-288-38-288-38l-222-252H992L769 363s-196-53-288 37L311 575l60 147-75 218 250 953c52 204 87 283 234 387l457 310c44 27 98 74 147 74s103-47 147-74l457-310c147-104 182-183 234-387l250-953z" }),
1738
+ /* @__PURE__ */ jsx("path", { fill: "#fff", d: "M1935 524s287 347 287 420c0 75-36 94-72 133l-215 230c-20 20-63 54-38 113 25 60 60 134 20 210-40 77-110 128-155 120a820 820 0 0 1-190-90c-38-25-160-126-160-165s126-110 150-124c23-16 130-78 132-102s2-30-30-90-88-140-80-192c10-52 100-80 167-105l207-78c16-8 12-15-36-20-48-4-183-22-244-5s-163 43-173 57c-8 14-16 14-7 62l58 315c4 40 12 67-30 77-44 10-117 27-142 27s-99-17-142-27-35-37-30-77c4-40 48-268 57-315 10-48 1-48-7-62-10-14-113-40-174-57-60-17-196 1-244 6-48 4-52 10-36 20l207 77c66 25 158 53 167 105 10 53-47 132-80 192s-32 66-30 90 110 86 132 102c24 15 150 85 150 124s-119 140-159 165a820 820 0 0 1-190 90c-45 8-115-43-156-120-40-76-4-150 20-210 25-60-17-92-38-113l-215-230c-35-37-71-57-71-131s287-420 287-420l273 44c32 0 103-27 168-50 65-20 110-22 110-22s44 0 110 22 136 50 168 50c33 0 275-47 275-47zm-215 1328c18 10 7 32-10 44l-254 198c-20 20-52 50-73 50s-52-30-73-50a13200 13200 0 0 0-255-198c-16-12-27-33-10-44l150-80a870 870 0 0 1 188-73c15 0 110 34 187 73l150 80z" }),
1739
+ /* @__PURE__ */ jsx("path", { fill: "url(#brave_b)", d: "m1999 363-224-253H992L769 363s-196-53-288 37c0 0 260-23 350 123l276 47c32 0 103-27 168-50 65-20 110-22 110-22s44 0 110 22 136 50 168 50c33 0 275-47 275-47 90-146 350-123 350-123-92-92-288-38-288-38" })
1740
+ ] }) });
1741
+ var BitgetWalletIcon = () => /* @__PURE__ */ jsx(IconFrame, { background: "#001F29", children: /* @__PURE__ */ jsx("svg", { width: "28", height: "28", viewBox: "0 0 512 512", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M219.948 95.7022C201.623 95.6929 183.33 95.6835 164.941 95.7116C153.822 95.7116 149.651 109.671 157.921 117.939L283.098 243.117C287.004 246.69 289.441 250.574 289.53 255.693C289.441 260.812 287.004 264.696 283.098 268.269L157.921 393.446C149.651 401.715 153.822 415.674 164.941 415.674C183.33 415.702 201.623 415.693 219.948 415.683C229.122 415.679 238.305 415.674 247.511 415.674C259.555 415.674 266.72 409.24 273.154 402.805L386.047 289.912C395.057 280.902 403.119 268.939 403.009 255.693C403.119 242.447 395.057 230.484 386.047 221.474L273.154 108.58C266.72 102.146 259.555 95.7116 247.511 95.7116C238.305 95.7116 229.122 95.7069 219.948 95.7022Z", fill: "#00F0FF" }) }) });
1742
+ var walletIconTheme = {
1743
+ metamask: "#F6851B",
1744
+ okx: "#050608",
1745
+ coinbase: "#0052FF",
1746
+ trust: "#3375FF",
1747
+ phantom: "#6C47FF",
1748
+ rabby: "#7084FF",
1749
+ rainbow: "#123F99",
1750
+ zerion: "#2962EF",
1751
+ brave: "#FF452A",
1752
+ bitget: "#00F0FF"
1753
+ };
1754
+ var WalletPlaceholder = ({ walletId, name }) => /* @__PURE__ */ jsx(IconFrame, { background: walletIconTheme[walletId] ?? colors.cardRaised, children: /* @__PURE__ */ jsx(
1755
+ "span",
1756
+ {
1757
+ style: {
1758
+ fontSize: 14,
1759
+ fontWeight: 700,
1760
+ color: walletIconTheme[walletId] ? "#FFFFFF" : colors.textSecondary,
1761
+ fontFamily: fonts.family
1762
+ },
1763
+ children: name.slice(0, 2).toUpperCase()
1764
+ }
1765
+ ) });
1766
+ var DefaultWalletIcon = ({
1767
+ walletId,
1768
+ name
1769
+ }) => {
1770
+ switch (walletId) {
1771
+ case "metamask":
1772
+ return /* @__PURE__ */ jsx(MetaMaskWalletIcon, {});
1773
+ case "okx":
1774
+ return /* @__PURE__ */ jsx(OKXWalletIcon, {});
1775
+ case "coinbase":
1776
+ return /* @__PURE__ */ jsx(CoinbaseWalletIcon, {});
1777
+ case "trust":
1778
+ return /* @__PURE__ */ jsx(TrustWalletIcon, {});
1779
+ case "phantom":
1780
+ return /* @__PURE__ */ jsx(PhantomWalletIcon, {});
1781
+ case "rabby":
1782
+ return /* @__PURE__ */ jsx(RabbyWalletIcon, {});
1783
+ case "rainbow":
1784
+ return /* @__PURE__ */ jsx(RainbowWalletIcon, {});
1785
+ case "zerion":
1786
+ return /* @__PURE__ */ jsx(ZerionWalletIcon, {});
1787
+ case "brave":
1788
+ return /* @__PURE__ */ jsx(BraveWalletIcon, {});
1789
+ case "bitget":
1790
+ return /* @__PURE__ */ jsx(BitgetWalletIcon, {});
1791
+ default:
1792
+ return /* @__PURE__ */ jsx(WalletPlaceholder, { walletId, name });
1793
+ }
1794
+ };
1795
+ var CloseButton = ({ onClick }) => /* @__PURE__ */ jsx(
1796
+ "button",
1797
+ {
1798
+ type: "button",
1799
+ onClick,
1800
+ "aria-label": "Close",
1801
+ style: {
1802
+ width: 30,
1803
+ height: 30,
1804
+ borderRadius: "50%",
1805
+ background: colors.card,
1806
+ border: "none",
1807
+ cursor: "pointer",
1808
+ display: "flex",
1809
+ alignItems: "center",
1810
+ justifyContent: "center",
1811
+ padding: 0,
1812
+ flexShrink: 0
1813
+ },
1814
+ children: /* @__PURE__ */ jsx("svg", { width: "17", height: "17", viewBox: "0 0 17 17", fill: "none", children: /* @__PURE__ */ jsx(
1815
+ "path",
1816
+ {
1817
+ d: "M4.25 4.25L12.75 12.75M12.75 4.25L4.25 12.75",
1818
+ stroke: colors.textPrimary,
1819
+ strokeWidth: "1.5",
1820
+ strokeLinecap: "round"
1821
+ }
1822
+ ) })
1823
+ }
1824
+ );
1825
+ var ModalFrame = ({
1826
+ onClose,
1827
+ width = 500,
1828
+ cardStyle,
1829
+ contentStyle,
1830
+ children
1831
+ }) => /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 14, alignItems: "flex-start" }, children: [
1832
+ /* @__PURE__ */ jsx(
1833
+ "div",
1834
+ {
1835
+ style: {
1836
+ width,
1837
+ background: colors.card,
1838
+ borderRadius: radii.card,
1839
+ overflow: "hidden",
1840
+ ...cardStyle
1841
+ },
1842
+ children: /* @__PURE__ */ jsx(
1843
+ "div",
1844
+ {
1845
+ style: {
1846
+ display: "flex",
1847
+ flexDirection: "column",
1848
+ minHeight: 0,
1849
+ fontFamily: fonts.family,
1850
+ color: colors.textPrimary,
1851
+ boxSizing: "border-box",
1852
+ ...contentStyle
1853
+ },
1854
+ children
1855
+ }
1856
+ )
1857
+ }
1858
+ ),
1859
+ /* @__PURE__ */ jsx(CloseButton, { onClick: onClose })
1860
+ ] }) });
1861
+ var SignInModalFrame = ({
1862
+ id,
1863
+ title,
1864
+ onClose,
1865
+ footer,
1866
+ children
1867
+ }) => /* @__PURE__ */ jsx(
1868
+ ModalFrame,
1869
+ {
1870
+ onClose,
1871
+ cardStyle: { padding: "32px 24px" },
1872
+ contentStyle: { alignItems: "center" },
1873
+ children: /* @__PURE__ */ jsxs("div", { style: { width: "100%", display: "flex", flexDirection: "column", gap: 24, alignItems: "center" }, id, children: [
1874
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: 24, fontWeight: 600, lineHeight: 1.4, textAlign: "center" }, children: title }),
1875
+ /* @__PURE__ */ jsx("div", { style: { width: "100%", display: "flex", flexDirection: "column", gap: 12, alignItems: "center" }, children }),
1876
+ footer
1877
+ ] })
1878
+ }
1879
+ );
1880
+ var SignInModalSocialSection = ({
1881
+ id,
1882
+ socialProviders,
1883
+ isBusy,
1884
+ loadingProvider,
1885
+ onSocialClick
1886
+ }) => /* @__PURE__ */ jsxs("div", { style: { width: "100%", display: "flex", flexDirection: "column", gap: 24 }, id, children: [
1887
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: socialProviders.map((provider) => {
1888
+ const isLoading = loadingProvider === provider.id;
1889
+ return /* @__PURE__ */ jsxs(
1890
+ "button",
1891
+ {
1892
+ type: "button",
1893
+ disabled: isBusy,
1894
+ onClick: () => onSocialClick(provider.id),
1895
+ style: {
1896
+ width: "100%",
1897
+ height: 48,
1898
+ borderRadius: radii.pill,
1899
+ border: `1px solid ${colors.border}`,
1900
+ background: "transparent",
1901
+ display: "flex",
1902
+ alignItems: "center",
1903
+ justifyContent: "center",
1904
+ gap: 12,
1905
+ cursor: isBusy ? "wait" : "pointer",
1906
+ padding: 12,
1907
+ boxSizing: "border-box",
1908
+ opacity: isLoading ? 0.6 : isBusy ? 0.8 : 1,
1909
+ transition: "opacity .15s"
1910
+ },
1911
+ children: [
1912
+ isLoading ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : provider.icon,
1913
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 16, fontWeight: 500, lineHeight: 1.4, color: colors.textPrimary, fontFamily: fonts.family }, children: isLoading ? "Signing in..." : provider.label })
1914
+ ]
1915
+ },
1916
+ provider.id
1917
+ );
1918
+ }) }),
1919
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 20, width: "100%" }, children: [
1920
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: colors.border } }),
1921
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textPrimary, opacity: 0.4, whiteSpace: "nowrap" }, children: "Or connect a wallet" }),
1922
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: colors.border } })
1923
+ ] })
1924
+ ] });
1925
+ var SignInModalWalletGrid = ({
1926
+ wallets,
1927
+ isBusy,
1928
+ loadingWalletId,
1929
+ expanded,
1930
+ showExpandToggle,
1931
+ onWalletClick,
1932
+ onToggleExpanded
1933
+ }) => /* @__PURE__ */ jsxs("div", { style: { width: "100%", display: "flex", flexDirection: "column", gap: 8, alignItems: "center", paddingTop: 12 }, children: [
1934
+ /* @__PURE__ */ jsx("div", { style: { width: "100%", display: "flex", flexWrap: "wrap", gap: "14px 0" }, children: wallets.map((wallet) => /* @__PURE__ */ jsxs(
1935
+ "button",
1936
+ {
1937
+ type: "button",
1938
+ disabled: isBusy,
1939
+ onClick: () => onWalletClick(wallet.id),
1940
+ style: {
1941
+ width: "25%",
1942
+ display: "flex",
1943
+ flexDirection: "column",
1944
+ alignItems: "center",
1945
+ gap: 4,
1946
+ background: "transparent",
1947
+ border: "none",
1948
+ cursor: isBusy ? "wait" : "pointer",
1949
+ padding: 0,
1950
+ opacity: loadingWalletId === wallet.id ? 0.7 : isBusy ? 0.85 : 1
1951
+ },
1952
+ children: [
1953
+ /* @__PURE__ */ jsx("div", { style: { width: 56, height: 56, display: "flex", alignItems: "center", justifyContent: "center" }, children: loadingWalletId === wallet.id ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : wallet.icon ?? /* @__PURE__ */ jsx(DefaultWalletIcon, { walletId: wallet.id, name: wallet.name }) }),
1954
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }, children: [
1955
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 12, fontWeight: 500, lineHeight: 1.4, color: colors.textPrimary, fontFamily: fonts.family, textAlign: "center", whiteSpace: "nowrap" }, children: wallet.name }),
1956
+ loadingWalletId === wallet.id ? /* @__PURE__ */ jsx("span", { style: { fontSize: 10, lineHeight: 1.4, color: colors.textSecondary, fontFamily: fonts.family }, children: "Connecting..." }) : wallet.installed ? /* @__PURE__ */ jsx("span", { style: { fontSize: 10, lineHeight: 1.4, color: colors.accent, fontFamily: fonts.family }, children: "Installed" }) : wallet.installUrl ? /* @__PURE__ */ jsx(
1957
+ "a",
1958
+ {
1959
+ href: wallet.installUrl,
1960
+ target: "_blank",
1961
+ rel: "noopener noreferrer",
1962
+ onClick: (event) => event.stopPropagation(),
1963
+ style: { fontSize: 10, lineHeight: 1.4, color: colors.textSecondary, fontFamily: fonts.family, textDecoration: "underline" },
1964
+ children: "Install"
1965
+ }
1966
+ ) : null
1967
+ ] })
1968
+ ]
1969
+ },
1970
+ wallet.id
1971
+ )) }),
1972
+ showExpandToggle && /* @__PURE__ */ jsx(
1973
+ "button",
1974
+ {
1975
+ type: "button",
1976
+ onClick: onToggleExpanded,
1977
+ style: {
1978
+ background: "transparent",
1979
+ border: "none",
1980
+ cursor: "pointer",
1981
+ display: "flex",
1982
+ alignItems: "center",
1983
+ justifyContent: "center",
1984
+ padding: 4
1985
+ },
1986
+ children: /* @__PURE__ */ jsx(ExpandIcon, { expanded })
1987
+ }
1988
+ )
1989
+ ] });
1990
+ var SignInModalFooter = ({
1991
+ privacyPolicyUrl,
1992
+ termsOfUseUrl
1993
+ }) => /* @__PURE__ */ jsx("div", { style: { padding: "12px 0", display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ jsxs("p", { style: { margin: 0, fontSize: 14, lineHeight: 1.4, color: colors.textSecondary, fontFamily: fonts.family, textAlign: "center" }, children: [
1994
+ "By continuing, I agree to the",
1995
+ " ",
1996
+ /* @__PURE__ */ jsx("a", { href: privacyPolicyUrl, style: { color: colors.textPrimary, textDecoration: "underline" }, target: "_blank", rel: "noopener noreferrer", children: "Privacy Policy" }),
1997
+ " ",
1998
+ "and",
1999
+ " ",
2000
+ /* @__PURE__ */ jsx("a", { href: termsOfUseUrl, style: { color: colors.textPrimary, textDecoration: "underline" }, target: "_blank", rel: "noopener noreferrer", children: "Terms of Use" })
2001
+ ] }) });
2002
+
2003
+ // src/auth/oidcRelay.ts
2004
+ function getRelayOrigin() {
2005
+ if (typeof window === "undefined") {
2006
+ throw new Error("OIDC relay requires a browser environment");
2007
+ }
2008
+ if (window.location.hostname === "localhost") {
2009
+ return window.location.origin;
2010
+ }
2011
+ const relayOrigin2 = getEnv("RELAY_ORIGIN");
2012
+ if (!relayOrigin2) {
2013
+ throw new Error("RELAY_ORIGIN is not configured");
2014
+ }
2015
+ return relayOrigin2;
2016
+ }
2017
+ function openRelayWindow(url, name) {
2018
+ const width = 420;
2019
+ const height = 640;
2020
+ const top = (window.innerHeight - height) / 2 + window.screenY;
2021
+ const left = (window.innerWidth - width) / 2 + window.screenX;
2022
+ return window.open(
2023
+ url,
2024
+ name,
2025
+ `dialog=yes,top=${top}px,left=${left}px,width=${width}px,height=${height}px`
2026
+ );
2027
+ }
2028
+ function waitForOidcToken(popup, relayOrigin2, timeoutMs = 12e4) {
2029
+ return new Promise((resolve, reject) => {
2030
+ if (!popup) {
2031
+ reject(new Error("Failed to open login popup"));
2032
+ return;
2033
+ }
2034
+ let settled = false;
2035
+ const cleanup = () => {
2036
+ clearTimeout(timeout);
2037
+ clearInterval(closedCheck);
2038
+ window.removeEventListener("message", onMessage);
2039
+ };
2040
+ const finish = (fn) => {
2041
+ if (settled) return;
2042
+ settled = true;
2043
+ cleanup();
2044
+ fn();
2045
+ };
2046
+ const timeout = window.setTimeout(() => {
2047
+ try {
2048
+ popup.close();
2049
+ } catch {
2050
+ }
2051
+ finish(() => reject(new Error("Login timeout")));
2052
+ }, timeoutMs);
2053
+ const onMessage = (event) => {
2054
+ if (event.origin !== relayOrigin2) return;
2055
+ if (event.data?.action !== "login") return;
2056
+ const payload = event.data?.data ?? {};
2057
+ if (payload.error) {
2058
+ try {
2059
+ popup.close();
2060
+ } catch {
2061
+ }
2062
+ finish(() => reject(new Error(String(payload.error))));
2063
+ return;
2064
+ }
2065
+ if (payload.oidcToken) {
2066
+ try {
2067
+ popup.close();
2068
+ } catch {
2069
+ }
2070
+ finish(() => resolve(payload.oidcToken));
2071
+ }
2072
+ };
2073
+ const closedCheck = window.setInterval(() => {
2074
+ if (popup.closed) {
2075
+ finish(() => reject(new Error("Login cancelled by user")));
2076
+ }
2077
+ }, 400);
2078
+ window.addEventListener("message", onMessage);
2079
+ });
2080
+ }
2081
+ function createOidcRelayAuth({
2082
+ stage,
2083
+ googleClientId,
2084
+ xClientId
2085
+ }) {
2086
+ const relayOrigin2 = getRelayOrigin();
2087
+ const buildUrl = (provider, clientId) => {
2088
+ const target = window.location.origin;
2089
+ const params = new URLSearchParams({
2090
+ target,
2091
+ stage,
2092
+ eventId: Date.now().toString(),
2093
+ action: "login",
2094
+ clientId
2095
+ });
2096
+ return `${relayOrigin2}/relay/${provider}?${params.toString()}`;
2097
+ };
2098
+ return {
2099
+ async loginByGoogle() {
2100
+ const popup = openRelayWindow(buildUrl("google", googleClientId), "Google login");
2101
+ return waitForOidcToken(popup, relayOrigin2);
2102
+ },
2103
+ async loginByX() {
2104
+ const popup = openRelayWindow(buildUrl("x", xClientId), "X login");
2105
+ return waitForOidcToken(popup, relayOrigin2);
2106
+ }
2107
+ };
2108
+ }
2109
+ function resolveOidcStage() {
2110
+ return getEnv("STAGE").toLowerCase() === "prod" ? "prod" : "dev";
2111
+ }
2112
+ var useSignInModalController = ({
2113
+ wallets,
2114
+ initialVisibleCount,
2115
+ onGoogleLogin,
2116
+ onTwitterLogin,
2117
+ onCubeSignerSession,
2118
+ onWalletConnected,
2119
+ onSocialLogin,
2120
+ onWalletSelect
2121
+ }) => {
2122
+ const [expanded, setExpanded] = useState(false);
2123
+ const [loadingProvider, setLoadingProvider] = useState(null);
2124
+ const [loadingWalletId, setLoadingWalletId] = useState(null);
2125
+ const defaultWalletRegistry = useMemo(() => createDefaultInjectedWalletRegistry(), []);
2126
+ const defaultWalletConnector = useMemo(
2127
+ () => new WalletConnector([
2128
+ ...defaultWalletRegistry.map((item) => item.provider)
2129
+ ]),
2130
+ [defaultWalletRegistry]
2131
+ );
2132
+ const resolvedWallets = useMemo(
2133
+ () => resolveWalletItems(wallets, defaultWalletRegistry),
2134
+ [defaultWalletRegistry, wallets]
2135
+ );
2136
+ const showExpandToggle = resolvedWallets.length > initialVisibleCount;
2137
+ const visibleWallets = expanded ? resolvedWallets : resolvedWallets.slice(0, initialVisibleCount);
2138
+ const isBusy = !!loadingProvider || !!loadingWalletId;
2139
+ const handleSocialClick = async (providerId) => {
2140
+ setLoadingProvider(providerId);
2141
+ try {
2142
+ const config = getSDKConfig();
2143
+ if (!config.cubeSigner) {
2144
+ throw new Error("cubeSigner config is required for social login");
2145
+ }
2146
+ const auth = createOidcRelayAuth({
2147
+ stage: resolveOidcStage(),
2148
+ googleClientId: config.googleClientId ?? "",
2149
+ xClientId: config.twitterClientId ?? ""
2150
+ });
2151
+ if (providerId === "google") {
2152
+ if (!config.googleClientId) {
2153
+ throw new Error("googleClientId is required for Google sign-in");
2154
+ }
2155
+ const oidcToken = await auth.loginByGoogle();
2156
+ const authSource = "google";
2157
+ WalletAccount.clearInstance();
2158
+ await WalletAccount.getInstance(oidcToken, authSource, config.cubeSigner);
2159
+ const session = WalletAccount.getWalletSession();
2160
+ const cubeSignerSession = WalletAccount.getCubeSignerSession();
2161
+ onGoogleLogin?.({ idToken: oidcToken });
2162
+ if (cubeSignerSession) onCubeSignerSession?.(cubeSignerSession);
2163
+ onSocialLogin?.(providerId);
2164
+ if (!session) {
2165
+ throw new Error("Failed to build wallet session from Google login");
2166
+ }
2167
+ return session;
2168
+ }
2169
+ if (providerId === "x") {
2170
+ if (!config.twitterClientId) {
2171
+ throw new Error("twitterClientId is required for X sign-in");
2172
+ }
2173
+ const oidcToken = await auth.loginByX();
2174
+ const authSource = "twitter";
2175
+ WalletAccount.clearInstance();
2176
+ await WalletAccount.getInstance(oidcToken, authSource, config.cubeSigner);
2177
+ const session = WalletAccount.getWalletSession();
2178
+ const cubeSignerSession = WalletAccount.getCubeSignerSession();
2179
+ onTwitterLogin?.({ code: "", codeVerifier: "", state: "" });
2180
+ if (cubeSignerSession) onCubeSignerSession?.(cubeSignerSession);
2181
+ onSocialLogin?.(providerId);
2182
+ if (!session) {
2183
+ throw new Error("Failed to build wallet session from X login");
2184
+ }
2185
+ return session;
2186
+ }
2187
+ throw new Error(`Unsupported social provider: ${providerId}`);
2188
+ } finally {
2189
+ setLoadingProvider(null);
2190
+ }
2191
+ };
2192
+ const handleWalletClick = async (walletId) => {
2193
+ if (isBusy) return null;
2194
+ const targetWallet = resolvedWallets.find((wallet) => wallet.id === walletId);
2195
+ if (!targetWallet) return null;
2196
+ if (targetWallet.installed === false && targetWallet.installUrl) return null;
2197
+ setLoadingWalletId(walletId);
2198
+ try {
2199
+ if (onWalletSelect) {
2200
+ await onWalletSelect(walletId);
2201
+ return null;
2202
+ }
2203
+ const builtInWallet = defaultWalletRegistry.find((item) => item.id === walletId);
2204
+ if (!builtInWallet || !builtInWallet.installed) return null;
2205
+ const session = await defaultWalletConnector.connect(walletId);
2206
+ onWalletConnected?.(session, walletId);
2207
+ return session;
2208
+ } catch (error) {
2209
+ console.error(`[predicate-market-sdk] Wallet connect failed for ${walletId}:`, error);
2210
+ throw error;
2211
+ } finally {
2212
+ setLoadingWalletId(null);
2213
+ }
2214
+ };
2215
+ return {
2216
+ expanded,
2217
+ loadingProvider,
2218
+ loadingWalletId,
2219
+ visibleWallets,
2220
+ showExpandToggle,
2221
+ isBusy,
2222
+ handleSocialClick,
2223
+ handleWalletClick,
2224
+ toggleExpanded: () => setExpanded((value) => !value)
2225
+ };
2226
+ };
2227
+ var variantStyles = {
2228
+ success: { bg: "rgba(41, 255, 155, 0.82)", border: "rgba(41, 255, 155, 0.53)" },
2229
+ error: { bg: "rgba(255, 107, 107, 0.82)", border: "rgba(255, 107, 107, 0.53)" },
2230
+ info: { bg: "rgba(126, 135, 162, 0.82)", border: "rgba(126, 135, 162, 0.55)" }
2231
+ };
2232
+ var Toast = ({ message, variant = "info", duration, onClose }) => {
2233
+ const style = variantStyles[variant];
2234
+ useEffect(() => {
2235
+ if (duration != null && duration > 0 && onClose) {
2236
+ const timer = setTimeout(onClose, duration);
2237
+ return () => clearTimeout(timer);
2238
+ }
2239
+ }, [duration, onClose]);
2240
+ return /* @__PURE__ */ jsx(
2241
+ "div",
2242
+ {
2243
+ style: {
2244
+ position: "fixed",
2245
+ top: 0,
2246
+ left: 0,
2247
+ right: 0,
2248
+ display: "flex",
2249
+ justifyContent: "center",
2250
+ paddingTop: 16,
2251
+ zIndex: 1e4,
2252
+ pointerEvents: "none"
2253
+ },
2254
+ children: /* @__PURE__ */ jsxs(
2255
+ "div",
2256
+ {
2257
+ role: "alert",
2258
+ style: {
2259
+ pointerEvents: "auto",
2260
+ display: "flex",
2261
+ alignItems: "center",
2262
+ gap: 10,
2263
+ padding: "12px 16px",
2264
+ borderRadius: radii.card,
2265
+ background: style.bg,
2266
+ border: `1px solid ${style.border}`,
2267
+ color: colors.textPrimary,
2268
+ fontSize: 14,
2269
+ lineHeight: 1.4,
2270
+ maxWidth: 360,
2271
+ boxSizing: "border-box"
2272
+ },
2273
+ children: [
2274
+ /* @__PURE__ */ jsx("span", { style: { flex: 1 }, children: message }),
2275
+ onClose ? /* @__PURE__ */ jsx(
2276
+ "button",
2277
+ {
2278
+ type: "button",
2279
+ "aria-label": "Dismiss",
2280
+ onClick: onClose,
2281
+ style: {
2282
+ padding: 4,
2283
+ margin: -4,
2284
+ border: "none",
2285
+ background: "transparent",
2286
+ color: colors.textSecondary,
2287
+ cursor: "pointer",
2288
+ borderRadius: 4,
2289
+ lineHeight: 1
2290
+ },
2291
+ children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: /* @__PURE__ */ jsx(
2292
+ "path",
2293
+ {
2294
+ d: "M3.5 3.5L10.5 10.5M10.5 3.5L3.5 10.5",
2295
+ stroke: "currentColor",
2296
+ strokeWidth: "1.5",
2297
+ strokeLinecap: "round"
2298
+ }
2299
+ ) })
2300
+ }
2301
+ ) : null
2302
+ ]
2303
+ }
2304
+ )
2305
+ }
2306
+ );
2307
+ };
2308
+ function clearSocialAccountInstance2() {
2309
+ try {
2310
+ clearSocialAccountInstance();
2311
+ const storage = typeof localStorage !== "undefined" ? localStorage : null;
2312
+ const adapterId = storage?.getItem("ab:wallet:adapterId");
2313
+ const session = sessionStore.getState().session;
2314
+ const isSocialSession = session?.walletType === "social" || session?.authSource === "google" || session?.authSource === "twitter" || adapterId === "cubist";
2315
+ if (!isSocialSession) return;
2316
+ sessionStore.clearSession();
2317
+ storage?.removeItem("ab:wallet:session");
2318
+ storage?.removeItem("ab:wallet:adapterId");
2319
+ } catch {
2320
+ clearSocialAccountInstance();
2321
+ sessionStore.clearSession();
2322
+ }
2323
+ }
2324
+ var SignInModal = ({
2325
+ title = "Welcome to PredicateMarket",
2326
+ socialProviders,
2327
+ wallets,
2328
+ initialVisibleCount,
2329
+ privacyPolicyUrl = "#",
2330
+ termsOfUseUrl = "#",
2331
+ onGoogleLogin,
2332
+ onTwitterLogin,
2333
+ onCubeSignerSession,
2334
+ onWalletConnected,
2335
+ onSocialLogin,
2336
+ onWalletSelect,
2337
+ onDismiss,
2338
+ onSuccess
2339
+ }) => {
2340
+ const sdkConfig2 = getSDKConfig();
2341
+ const effectiveSocialProviders = resolveSocialProviders(
2342
+ socialProviders ?? sdkConfig2.signIn?.socialProviders
2343
+ );
2344
+ const effectiveWallets = wallets ?? sdkConfig2.signIn?.wallets;
2345
+ const effectiveInitialVisibleCount = initialVisibleCount ?? sdkConfig2.signIn?.initialVisibleCount ?? 5;
2346
+ const [toastError, setToastError] = useState(null);
2347
+ const {
2348
+ expanded,
2349
+ loadingProvider,
2350
+ loadingWalletId,
2351
+ visibleWallets,
2352
+ showExpandToggle,
2353
+ isBusy,
2354
+ handleSocialClick,
2355
+ handleWalletClick,
2356
+ toggleExpanded
2357
+ } = useSignInModalController({
2358
+ wallets: effectiveWallets,
2359
+ initialVisibleCount: effectiveInitialVisibleCount,
2360
+ onGoogleLogin,
2361
+ onTwitterLogin,
2362
+ onCubeSignerSession,
2363
+ onWalletConnected,
2364
+ onSocialLogin,
2365
+ onWalletSelect
2366
+ });
2367
+ return /* @__PURE__ */ jsxs(
2368
+ SignInModalFrame,
2369
+ {
2370
+ id: "SignInModalFrame",
2371
+ title,
2372
+ onClose: onDismiss,
2373
+ footer: /* @__PURE__ */ jsx(
2374
+ SignInModalFooter,
2375
+ {
2376
+ privacyPolicyUrl,
2377
+ termsOfUseUrl
2378
+ }
2379
+ ),
2380
+ children: [
2381
+ toastError ? /* @__PURE__ */ jsx(
2382
+ Toast,
2383
+ {
2384
+ message: toastError,
2385
+ variant: "error",
2386
+ duration: 5e3,
2387
+ onClose: () => setToastError(null)
2388
+ }
2389
+ ) : null,
2390
+ /* @__PURE__ */ jsx(
2391
+ SignInModalSocialSection,
2392
+ {
2393
+ id: "SignInModalSocialSection",
2394
+ socialProviders: effectiveSocialProviders,
2395
+ isBusy,
2396
+ loadingProvider,
2397
+ onSocialClick: async (providerId) => {
2398
+ try {
2399
+ const session = await handleSocialClick(providerId);
2400
+ if (!session) return;
2401
+ const normalizedAuthSource = providerId === "x" ? "twitter" : providerId;
2402
+ onSuccess?.({
2403
+ ...session,
2404
+ walletType: session.walletType ?? "social",
2405
+ authSource: session.authSource ?? normalizedAuthSource
2406
+ });
2407
+ } catch (error) {
2408
+ const msg = error instanceof Error ? error.message : "Social login failed";
2409
+ setToastError(msg);
2410
+ }
2411
+ }
2412
+ }
2413
+ ),
2414
+ /* @__PURE__ */ jsx(
2415
+ SignInModalWalletGrid,
2416
+ {
2417
+ wallets: visibleWallets,
2418
+ isBusy,
2419
+ loadingWalletId,
2420
+ expanded,
2421
+ showExpandToggle,
2422
+ onWalletClick: async (walletId) => {
2423
+ try {
2424
+ const session = await handleWalletClick(walletId);
2425
+ if (session) {
2426
+ onSuccess?.(session);
2427
+ }
2428
+ } catch (error) {
2429
+ const msg = error instanceof Error ? error.message : "Wallet connect failed";
2430
+ setToastError(msg);
2431
+ }
2432
+ },
2433
+ onToggleExpanded: toggleExpanded
2434
+ }
2435
+ )
2436
+ ]
2437
+ }
2438
+ );
2439
+ };
2440
+ var placeholderIcon = (label) => /* @__PURE__ */ jsx(
2441
+ "div",
2442
+ {
2443
+ style: {
2444
+ width: 40,
2445
+ height: 40,
2446
+ borderRadius: "12px",
2447
+ background: colors.cardRaised,
2448
+ display: "flex",
2449
+ alignItems: "center",
2450
+ justifyContent: "center",
2451
+ color: colors.textSecondary,
2452
+ fontWeight: 600
2453
+ },
2454
+ children: label.slice(0, 2).toUpperCase()
2455
+ }
2456
+ );
2457
+ var WalletSelectionModal = ({
2458
+ title = "Connect Wallet",
2459
+ options,
2460
+ onSelect
2461
+ }) => {
2462
+ const sections = [
2463
+ {
2464
+ id: "social",
2465
+ label: "Social Wallets",
2466
+ items: options.filter((item) => item.category === "social")
2467
+ },
2468
+ {
2469
+ id: "plugin",
2470
+ label: "Plugin Wallets",
2471
+ items: options.filter((item) => item.category === "plugin")
2472
+ }
2473
+ ].filter((section) => section.items.length > 0);
2474
+ return /* @__PURE__ */ jsxs(
2475
+ "div",
2476
+ {
2477
+ style: {
2478
+ width: "min(720px, 90vw)",
2479
+ background: colors.card,
2480
+ borderRadius: radii.xl,
2481
+ border: `1px solid ${colors.border}`,
2482
+ padding: "40px",
2483
+ display: "flex",
2484
+ flexDirection: "column",
2485
+ gap: 32,
2486
+ color: colors.textPrimary,
2487
+ fontFamily: fonts.family
2488
+ },
2489
+ children: [
2490
+ /* @__PURE__ */ jsxs("div", { children: [
2491
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 26, fontWeight: 600 }, children: title }),
2492
+ /* @__PURE__ */ jsx("p", { style: { color: colors.textSecondary, marginTop: 8 }, children: "Choose social or plugin wallets" })
2493
+ ] }),
2494
+ sections.map((section) => /* @__PURE__ */ jsxs("section", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
2495
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 14, textTransform: "uppercase", letterSpacing: 1.5, color: colors.textSecondary }, children: section.label }),
2496
+ /* @__PURE__ */ jsx(
2497
+ "div",
2498
+ {
2499
+ style: {
2500
+ display: "grid",
2501
+ gap: 16,
2502
+ gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))"
2503
+ },
2504
+ children: section.items.map((option) => /* @__PURE__ */ jsxs(
2505
+ "button",
2506
+ {
2507
+ onClick: () => onSelect?.(option.id),
2508
+ style: {
2509
+ borderRadius: radii.lg,
2510
+ border: `1px solid ${colors.border}`,
2511
+ background: colors.cardRaised,
2512
+ padding: "20px",
2513
+ display: "flex",
2514
+ gap: 14,
2515
+ alignItems: "center",
2516
+ textAlign: "left",
2517
+ cursor: "pointer",
2518
+ color: colors.textPrimary
2519
+ },
2520
+ children: [
2521
+ option.icon ?? placeholderIcon(option.label),
2522
+ /* @__PURE__ */ jsxs("div", { children: [
2523
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 600 }, children: option.label }),
2524
+ /* @__PURE__ */ jsx("div", { style: { color: colors.textSecondary, fontSize: 14 }, children: option.description })
2525
+ ] })
2526
+ ]
2527
+ },
2528
+ option.id
2529
+ ))
2530
+ }
2531
+ )
2532
+ ] }, section.id))
2533
+ ]
2534
+ }
2535
+ );
2536
+ };
2537
+ var StepIndicator = ({ steps, stepActive, activeStep = 0 }) => {
2538
+ return /* @__PURE__ */ jsx(
2539
+ "div",
2540
+ {
2541
+ style: {
2542
+ display: "flex",
2543
+ flexDirection: "column",
2544
+ alignItems: "center",
2545
+ width: 20,
2546
+ paddingTop: 4,
2547
+ flexShrink: 0
2548
+ },
2549
+ children: Array.from({ length: steps }, (_, i) => {
2550
+ const isActive = stepActive && stepActive.length > i ? stepActive[i] : i <= activeStep;
2551
+ const isLast = i === steps - 1;
2552
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center" }, children: [
2553
+ /* @__PURE__ */ jsx(
2554
+ "div",
2555
+ {
2556
+ style: {
2557
+ width: 20,
2558
+ height: 20,
2559
+ borderRadius: "50%",
2560
+ border: `2px solid ${isActive ? colors.stepActive : colors.stepInactive}`,
2561
+ display: "flex",
2562
+ alignItems: "center",
2563
+ justifyContent: "center",
2564
+ boxSizing: "border-box"
2565
+ },
2566
+ children: /* @__PURE__ */ jsx(
2567
+ "div",
2568
+ {
2569
+ style: {
2570
+ width: 7.5,
2571
+ height: 7.5,
2572
+ borderRadius: "50%",
2573
+ background: isActive ? colors.stepActive : colors.stepInactive
2574
+ }
2575
+ }
2576
+ )
2577
+ }
2578
+ ),
2579
+ !isLast && /* @__PURE__ */ jsx(
2580
+ "div",
2581
+ {
2582
+ style: {
2583
+ width: 1,
2584
+ height: 87,
2585
+ background: isActive ? colors.stepActive : colors.stepInactive,
2586
+ opacity: 0.3
2587
+ }
2588
+ }
2589
+ )
2590
+ ] }, i);
2591
+ })
2592
+ }
2593
+ );
2594
+ };
2595
+ var Chevron = ({ up }) => /* @__PURE__ */ jsx(
2596
+ "svg",
2597
+ {
2598
+ width: "16",
2599
+ height: "16",
2600
+ viewBox: "0 0 16 16",
2601
+ fill: "none",
2602
+ style: { transition: "transform .2s", transform: up ? "rotate(180deg)" : "none" },
2603
+ children: /* @__PURE__ */ jsx("path", { d: "M4 6L8 10L12 6", stroke: colors.textSecondary, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
2604
+ }
2605
+ );
2606
+ var DropdownField = ({
2607
+ label,
2608
+ placeholder,
2609
+ value,
2610
+ icon,
2611
+ focused,
2612
+ options,
2613
+ onSelect,
2614
+ onClick
2615
+ }) => {
2616
+ const [open, setOpen] = useState(false);
2617
+ const [triggerFocused, setTriggerFocused] = useState(false);
2618
+ const ref = useRef(null);
2619
+ useEffect(() => {
2620
+ if (!open) return;
2621
+ const handler = (e) => {
2622
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
2623
+ };
2624
+ document.addEventListener("mousedown", handler);
2625
+ return () => document.removeEventListener("mousedown", handler);
2626
+ }, [open]);
2627
+ const hasOptions = options && options.length > 0;
2628
+ const handleClick = () => {
2629
+ if (hasOptions) {
2630
+ setOpen((p) => !p);
2631
+ } else {
2632
+ onClick?.();
2633
+ }
2634
+ };
2635
+ const handleSelect = (id) => {
2636
+ onSelect?.(id);
2637
+ setOpen(false);
2638
+ };
2639
+ const selected = hasOptions ? options.find((o) => o.id === value) : void 0;
2640
+ return /* @__PURE__ */ jsxs("div", { ref, style: { display: "flex", flexDirection: "column", gap: 8, width: "100%", position: "relative" }, children: [
2641
+ /* @__PURE__ */ jsx(
2642
+ "span",
2643
+ {
2644
+ style: {
2645
+ fontSize: 14,
2646
+ fontWeight: 400,
2647
+ lineHeight: 1.4,
2648
+ color: colors.textPrimary,
2649
+ fontFamily: fonts.family
2650
+ },
2651
+ children: label
2652
+ }
2653
+ ),
2654
+ /* @__PURE__ */ jsxs(
2655
+ "button",
2656
+ {
2657
+ type: "button",
2658
+ onClick: handleClick,
2659
+ onFocus: () => setTriggerFocused(true),
2660
+ onBlur: () => setTriggerFocused(false),
2661
+ style: {
2662
+ display: "flex",
2663
+ alignItems: "center",
2664
+ justifyContent: "space-between",
2665
+ height: 44,
2666
+ padding: "0 16px",
2667
+ borderRadius: radii.input,
2668
+ border: `1px solid ${open || triggerFocused ? colors.borderFocused : colors.border}`,
2669
+ background: "transparent",
2670
+ cursor: "pointer",
2671
+ fontFamily: fonts.family,
2672
+ width: "100%",
2673
+ boxSizing: "border-box"
2674
+ },
2675
+ children: [
2676
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
2677
+ selected?.icon ?? icon,
2678
+ /* @__PURE__ */ jsx(
2679
+ "span",
2680
+ {
2681
+ style: {
2682
+ fontSize: 14,
2683
+ lineHeight: 1.4,
2684
+ color: value ? colors.textPrimary : colors.textSecondary,
2685
+ fontFamily: fonts.family
2686
+ },
2687
+ children: selected?.label ?? value ?? placeholder
2688
+ }
2689
+ )
2690
+ ] }),
2691
+ /* @__PURE__ */ jsx(Chevron, { up: open })
2692
+ ]
2693
+ }
2694
+ ),
2695
+ open && hasOptions && /* @__PURE__ */ jsx(
2696
+ "div",
2697
+ {
2698
+ className: "dropdown-list-item",
2699
+ style: {
2700
+ position: "absolute",
2701
+ top: "calc(100% + 4px)",
2702
+ left: 0,
2703
+ right: 0,
2704
+ zIndex: 10,
2705
+ borderRadius: radii.input,
2706
+ border: `1px solid ${colors.border}`,
2707
+ background: colors.card,
2708
+ overflow: "hidden",
2709
+ boxShadow: "0 8px 24px rgba(0,0,0,0.4)"
2710
+ },
2711
+ children: options.map((opt) => /* @__PURE__ */ jsxs(
2712
+ "button",
2713
+ {
2714
+ type: "button",
2715
+ onClick: () => handleSelect(opt.id),
2716
+ style: {
2717
+ display: "flex",
2718
+ alignItems: "center",
2719
+ gap: 10,
2720
+ width: "100%",
2721
+ padding: "10px 16px",
2722
+ border: "none",
2723
+ background: opt.id === value ? "rgba(255,255,255,0.06)" : "transparent",
2724
+ cursor: "pointer",
2725
+ fontFamily: fonts.family,
2726
+ textAlign: "left",
2727
+ transition: "background .12s"
2728
+ },
2729
+ onMouseEnter: (e) => {
2730
+ e.currentTarget.style.background = "rgba(255,255,255,0.08)";
2731
+ },
2732
+ onMouseLeave: (e) => {
2733
+ e.currentTarget.style.background = opt.id === value ? "rgba(255,255,255,0.06)" : "transparent";
2734
+ },
2735
+ children: [
2736
+ opt.icon && /* @__PURE__ */ jsx("div", { style: { width: 28, height: 28, flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center" }, children: opt.icon }),
2737
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 1 }, children: [
2738
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, fontWeight: 500, color: colors.textPrimary }, children: opt.label }),
2739
+ opt.subtitle && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: colors.textSecondary }, children: opt.subtitle })
2740
+ ] })
2741
+ ]
2742
+ },
2743
+ opt.id
2744
+ ))
2745
+ }
2746
+ )
2747
+ ] });
2748
+ };
2749
+ function getRemaining(expiresAt) {
2750
+ const end = typeof expiresAt === "string" ? new Date(expiresAt).getTime() : expiresAt;
2751
+ return Math.max(0, Math.floor((end - Date.now()) / 1e3));
2752
+ }
2753
+ function formatRemaining(seconds) {
2754
+ const m = Math.floor(seconds / 60);
2755
+ const s = seconds % 60;
2756
+ return `${m}:${s.toString().padStart(2, "0")}`;
2757
+ }
2758
+ function Countdown({
2759
+ expiresAt,
2760
+ expiredLabel = "Expired",
2761
+ style,
2762
+ isExpired = false,
2763
+ onExpired
2764
+ }) {
2765
+ const [remaining, setRemaining] = useState(() => getRemaining(expiresAt));
2766
+ const hasFiredExpired = useRef(false);
2767
+ useEffect(() => {
2768
+ hasFiredExpired.current = false;
2769
+ }, [expiresAt]);
2770
+ useEffect(() => {
2771
+ if (isExpired) {
2772
+ setRemaining(0);
2773
+ return;
2774
+ }
2775
+ const tick = () => {
2776
+ const r = getRemaining(expiresAt);
2777
+ setRemaining(r);
2778
+ if (r <= 0 && onExpired && !hasFiredExpired.current) {
2779
+ hasFiredExpired.current = true;
2780
+ onExpired();
2781
+ }
2782
+ };
2783
+ tick();
2784
+ const id = setInterval(tick, 1e3);
2785
+ return () => clearInterval(id);
2786
+ }, [expiresAt, isExpired, onExpired]);
2787
+ const text = remaining <= 0 ? expiredLabel : formatRemaining(remaining);
2788
+ const color = remaining <= 0 ? colors.warning : colors.textSecondary;
2789
+ return /* @__PURE__ */ jsxs("span", { style: { fontSize: 12, color, fontFamily: fonts.family, ...style }, children: [
2790
+ "Expires in ",
2791
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "#fff" }, children: text })
2792
+ ] });
2793
+ }
2794
+ function generateMatrix(data) {
2795
+ const qr = qrcode(0, "H");
2796
+ qr.addData(data);
2797
+ qr.make();
2798
+ const count = qr.getModuleCount();
2799
+ const matrix = [];
2800
+ for (let r = 0; r < count; r++) {
2801
+ const row = [];
2802
+ for (let c = 0; c < count; c++) {
2803
+ row.push(qr.isDark(r, c));
2804
+ }
2805
+ matrix.push(row);
2806
+ }
2807
+ return matrix;
2808
+ }
2809
+ function isFinderZone(row, col, size) {
2810
+ return row < 7 && col < 7 || row < 7 && col >= size - 7 || row >= size - 7 && col < 7;
2811
+ }
2812
+ var FinderEye = ({ ox, oy, s }) => /* @__PURE__ */ jsxs(Fragment, { children: [
2813
+ /* @__PURE__ */ jsx("rect", { x: ox, y: oy, width: 7 * s, height: 7 * s, rx: s * 1.4, ry: s * 1.4, fill: "#fff" }),
2814
+ /* @__PURE__ */ jsx(
2815
+ "rect",
2816
+ {
2817
+ x: ox + s,
2818
+ y: oy + s,
2819
+ width: 5 * s,
2820
+ height: 5 * s,
2821
+ rx: s * 0.9,
2822
+ ry: s * 0.9,
2823
+ fill: colors.background
2824
+ }
2825
+ ),
2826
+ /* @__PURE__ */ jsx(
2827
+ "rect",
2828
+ {
2829
+ x: ox + 2 * s,
2830
+ y: oy + 2 * s,
2831
+ width: 3 * s,
2832
+ height: 3 * s,
2833
+ rx: s * 0.7,
2834
+ ry: s * 0.7,
2835
+ fill: "#fff"
2836
+ }
2837
+ )
2838
+ ] });
2839
+ var SVG_SIZE = 220;
2840
+ var QUIET_ZONE = 2;
2841
+ var StyledQR = ({ data }) => {
2842
+ const matrix = useMemo(() => generateMatrix(data), [data]);
2843
+ const n = matrix.length;
2844
+ const total = n + QUIET_ZONE * 2;
2845
+ const cell = SVG_SIZE / total;
2846
+ const off = QUIET_ZONE * cell;
2847
+ const dotR = cell * 0.42;
2848
+ const centerClearR = 3;
2849
+ const cx = n / 2;
2850
+ const cy = n / 2;
2851
+ const dots = [];
2852
+ for (let r = 0; r < n; r++) {
2853
+ for (let c = 0; c < n; c++) {
2854
+ if (!matrix[r][c]) continue;
2855
+ if (isFinderZone(r, c, n)) continue;
2856
+ if (Math.abs(c - cx) < centerClearR && Math.abs(r - cy) < centerClearR) continue;
2857
+ dots.push(
2858
+ /* @__PURE__ */ jsx(
2859
+ "circle",
2860
+ {
2861
+ cx: off + c * cell + cell / 2,
2862
+ cy: off + r * cell + cell / 2,
2863
+ r: dotR,
2864
+ fill: "#fff"
2865
+ },
2866
+ `${r}-${c}`
2867
+ )
2868
+ );
2869
+ }
2870
+ }
2871
+ return /* @__PURE__ */ jsxs(
2872
+ "svg",
2873
+ {
2874
+ width: SVG_SIZE,
2875
+ height: SVG_SIZE,
2876
+ viewBox: `0 0 ${SVG_SIZE} ${SVG_SIZE}`,
2877
+ style: { borderRadius: 12 },
2878
+ children: [
2879
+ /* @__PURE__ */ jsx("rect", { width: SVG_SIZE, height: SVG_SIZE, fill: colors.background }),
2880
+ /* @__PURE__ */ jsx(FinderEye, { ox: off, oy: off, s: cell }),
2881
+ /* @__PURE__ */ jsx(FinderEye, { ox: off + (n - 7) * cell, oy: off, s: cell }),
2882
+ /* @__PURE__ */ jsx(FinderEye, { ox: off, oy: off + (n - 7) * cell, s: cell }),
2883
+ dots
2884
+ ]
2885
+ }
2886
+ );
2887
+ };
2888
+ var CopyIcon = () => /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: [
2889
+ /* @__PURE__ */ jsx("rect", { x: "4.5", y: "4.5", width: "7", height: "7", rx: "1.5", stroke: colors.textPrimary, strokeWidth: "1.2" }),
2890
+ /* @__PURE__ */ jsx(
2891
+ "path",
2892
+ {
2893
+ d: "M9.5 4.5V3.5C9.5 2.67 8.83 2 8 2H3.5C2.67 2 2 2.67 2 3.5V8C2 8.83 2.67 9.5 3.5 9.5H4.5",
2894
+ stroke: colors.textPrimary,
2895
+ strokeWidth: "1.2"
2896
+ }
2897
+ )
2898
+ ] });
2899
+ var DepositDetailsPanel = ({
2900
+ address,
2901
+ tokenIcon,
2902
+ minimumDeposit,
2903
+ onCopyAddress
2904
+ }) => {
2905
+ const canCopy = typeof address === "string" && address.trim().length > 0;
2906
+ const handleCopy = async () => {
2907
+ if (!canCopy) return;
2908
+ try {
2909
+ if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
2910
+ await navigator.clipboard.writeText(address);
2911
+ } else {
2912
+ const el = document.createElement("textarea");
2913
+ el.value = address;
2914
+ el.setAttribute("readonly", "");
2915
+ el.style.position = "absolute";
2916
+ el.style.left = "-9999px";
2917
+ document.body.appendChild(el);
2918
+ el.select();
2919
+ try {
2920
+ document.execCommand("copy");
2921
+ } catch {
2922
+ }
2923
+ document.body.removeChild(el);
2924
+ }
2925
+ } finally {
2926
+ onCopyAddress?.(address);
2927
+ }
2928
+ };
2929
+ return /* @__PURE__ */ jsxs(
2930
+ "div",
2931
+ {
2932
+ style: {
2933
+ display: "flex",
2934
+ flexDirection: "column",
2935
+ alignItems: "center",
2936
+ gap: 16,
2937
+ padding: "20px",
2938
+ borderRadius: radii.card,
2939
+ border: `1px solid ${colors.border}`,
2940
+ fontFamily: fonts.family
2941
+ },
2942
+ children: [
2943
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", display: "inline-flex" }, children: [
2944
+ /* @__PURE__ */ jsx(StyledQR, { data: address }),
2945
+ tokenIcon && /* @__PURE__ */ jsx(
2946
+ "div",
2947
+ {
2948
+ style: {
2949
+ position: "absolute",
2950
+ top: "50%",
2951
+ left: "50%",
2952
+ transform: "translate(-50%, -50%)",
2953
+ width: 36,
2954
+ height: 36,
2955
+ borderRadius: "50%",
2956
+ background: "#3B5998",
2957
+ display: "flex",
2958
+ alignItems: "center",
2959
+ justifyContent: "center",
2960
+ boxShadow: `0 0 0 3px ${colors.background}`
2961
+ },
2962
+ children: tokenIcon
2963
+ }
2964
+ )
2965
+ ] }),
2966
+ /* @__PURE__ */ jsx("div", { style: { width: "100%", display: "flex", flexDirection: "column", gap: 8 }, children: /* @__PURE__ */ jsx(
2967
+ "div",
2968
+ {
2969
+ style: {
2970
+ padding: "10px 14px",
2971
+ borderRadius: radii.input,
2972
+ background: "rgba(255,255,255,0.05)",
2973
+ fontSize: 13,
2974
+ color: colors.textPrimary,
2975
+ wordBreak: "break-all",
2976
+ lineHeight: 1.5
2977
+ },
2978
+ children: address
2979
+ }
2980
+ ) }),
2981
+ minimumDeposit && /* @__PURE__ */ jsxs(
2982
+ "div",
2983
+ {
2984
+ style: {
2985
+ width: "100%",
2986
+ display: "flex",
2987
+ justifyContent: "space-between",
2988
+ fontSize: 13
2989
+ },
2990
+ children: [
2991
+ /* @__PURE__ */ jsx("span", { style: { color: colors.textSecondary }, children: "Minimum deposit" }),
2992
+ /* @__PURE__ */ jsx("span", { style: { color: colors.textPrimary, fontWeight: 500 }, children: minimumDeposit })
2993
+ ]
2994
+ }
2995
+ ),
2996
+ /* @__PURE__ */ jsxs(
2997
+ "button",
2998
+ {
2999
+ type: "button",
3000
+ onClick: handleCopy,
3001
+ disabled: !canCopy,
3002
+ style: {
3003
+ display: "flex",
3004
+ alignItems: "center",
3005
+ gap: 6,
3006
+ padding: "10px 28px",
3007
+ borderRadius: radii.pill,
3008
+ border: `1px solid ${colors.borderStrong}`,
3009
+ background: "transparent",
3010
+ color: colors.textPrimary,
3011
+ fontSize: 14,
3012
+ fontWeight: 500,
3013
+ cursor: canCopy ? "pointer" : "not-allowed",
3014
+ opacity: canCopy ? 1 : 0.6,
3015
+ fontFamily: fonts.family,
3016
+ transition: "background .15s"
3017
+ },
3018
+ onMouseEnter: (e) => {
3019
+ if (!canCopy) return;
3020
+ e.currentTarget.style.background = "rgba(255,255,255,0.06)";
3021
+ },
3022
+ onMouseLeave: (e) => {
3023
+ e.currentTarget.style.background = "transparent";
3024
+ },
3025
+ children: [
3026
+ /* @__PURE__ */ jsx(CopyIcon, {}),
3027
+ "Copy address"
3028
+ ]
3029
+ }
3030
+ )
3031
+ ]
3032
+ }
3033
+ );
3034
+ };
3035
+ var LockIcon = () => /* @__PURE__ */ jsxs("svg", { width: "48", height: "48", viewBox: "0 0 48 48", fill: "none", children: [
3036
+ /* @__PURE__ */ jsx("rect", { x: "10", y: "22", width: "28", height: "20", rx: "4", stroke: colors.textSecondary, strokeWidth: "2" }),
3037
+ /* @__PURE__ */ jsx("path", { d: "M16 22V16C16 11.5817 19.5817 8 24 8C28.4183 8 32 11.5817 32 16V22", stroke: colors.textSecondary, strokeWidth: "2", strokeLinecap: "round" }),
3038
+ /* @__PURE__ */ jsx("circle", { cx: "24", cy: "33", r: "3", fill: colors.textSecondary })
3039
+ ] });
3040
+ var LoginRequiredOverlay = ({
3041
+ title,
3042
+ onSignIn,
3043
+ onClose
3044
+ }) => /* @__PURE__ */ jsx(ModalFrame, { onClose, contentStyle: { padding: "48px 24px" }, children: /* @__PURE__ */ jsxs(
3045
+ "div",
3046
+ {
3047
+ style: {
3048
+ display: "flex",
3049
+ flexDirection: "column",
3050
+ alignItems: "center",
3051
+ gap: 24,
3052
+ textAlign: "center"
3053
+ },
3054
+ children: [
3055
+ /* @__PURE__ */ jsx(LockIcon, {}),
3056
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
3057
+ /* @__PURE__ */ jsx(
3058
+ "h2",
3059
+ {
3060
+ style: {
3061
+ margin: 0,
3062
+ fontSize: 20,
3063
+ fontWeight: 600,
3064
+ color: colors.textPrimary
3065
+ },
3066
+ children: title
3067
+ }
3068
+ ),
3069
+ /* @__PURE__ */ jsx(
3070
+ "p",
3071
+ {
3072
+ style: {
3073
+ margin: 0,
3074
+ fontSize: 14,
3075
+ color: colors.textSecondary,
3076
+ lineHeight: 1.5
3077
+ },
3078
+ children: "Please sign in to continue"
3079
+ }
3080
+ )
3081
+ ] }),
3082
+ onSignIn && /* @__PURE__ */ jsx(
3083
+ "button",
3084
+ {
3085
+ type: "button",
3086
+ onClick: onSignIn,
3087
+ style: {
3088
+ padding: "12px 48px",
3089
+ borderRadius: radii.full,
3090
+ border: "none",
3091
+ background: colors.textPrimary,
3092
+ color: "#15181D",
3093
+ fontSize: 16,
3094
+ fontWeight: 500,
3095
+ fontFamily: fonts.family,
3096
+ cursor: "pointer"
3097
+ },
3098
+ children: "Sign In"
3099
+ }
3100
+ )
3101
+ ]
3102
+ }
3103
+ ) });
3104
+ function useSession() {
3105
+ const [session, setSession] = useState(
3106
+ () => sessionStore.getState().session
3107
+ );
3108
+ useEffect(() => {
3109
+ const unsub = sessionStore.on("session:changed", setSession);
3110
+ return () => {
3111
+ unsub();
3112
+ };
3113
+ }, []);
3114
+ return session;
3115
+ }
3116
+ var BackArrow = () => /* @__PURE__ */ jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M15 6L9 12L15 18", stroke: colors.textPrimary, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
3117
+ var TransferIcon = () => /* @__PURE__ */ jsxs("svg", { width: "36", height: "36", viewBox: "0 0 36 36", fill: "none", children: [
3118
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "18", r: "18", fill: "rgba(255,255,255,0.08)" }),
3119
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "18", r: "7", stroke: colors.textPrimary, strokeWidth: "1.5" }),
3120
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "18", r: "2.5", fill: colors.textPrimary }),
3121
+ /* @__PURE__ */ jsx("path", { d: "M18 7V11", stroke: colors.textPrimary, strokeWidth: "1.5", strokeLinecap: "round" }),
3122
+ /* @__PURE__ */ jsx("path", { d: "M18 25V29", stroke: colors.textPrimary, strokeWidth: "1.5", strokeLinecap: "round" }),
3123
+ /* @__PURE__ */ jsx("path", { d: "M7 18H11", stroke: colors.textPrimary, strokeWidth: "1.5", strokeLinecap: "round" }),
3124
+ /* @__PURE__ */ jsx("path", { d: "M25 18H29", stroke: colors.textPrimary, strokeWidth: "1.5", strokeLinecap: "round" })
3125
+ ] });
3126
+ var FiatIcon = () => /* @__PURE__ */ jsxs("svg", { width: "36", height: "36", viewBox: "0 0 36 36", fill: "none", children: [
3127
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "18", r: "18", fill: "rgba(255,255,255,0.06)" }),
3128
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "18", r: "10", stroke: colors.textSecondary, strokeWidth: "1.5" }),
3129
+ /* @__PURE__ */ jsx("path", { d: "M18 12V24", stroke: colors.textSecondary, strokeWidth: "1.5", strokeLinecap: "round" }),
3130
+ /* @__PURE__ */ jsx("path", { d: "M15 15.5C15 14.12 16.34 13 18 13C19.66 13 21 14.12 21 15.5C21 16.88 19.66 18 18 18C16.34 18 15 19.12 15 20.5C15 21.88 16.34 23 18 23C19.66 23 21 21.88 21 20.5", stroke: colors.textSecondary, strokeWidth: "1.5", strokeLinecap: "round" })
3131
+ ] });
3132
+ var DefaultCryptoIcons = () => {
3133
+ const tokens = [
3134
+ { label: "B", bg: "#F7931A" },
3135
+ { label: "E", bg: "#627EEA" },
3136
+ { label: "\u2261", bg: "#26A17B" },
3137
+ { label: "$", bg: "#2775CA" },
3138
+ { label: "S", bg: "#9945FF" },
3139
+ { label: "A", bg: "#E84142" }
3140
+ ];
3141
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 0 }, children: tokens.map((t, i) => /* @__PURE__ */ jsx(
3142
+ "div",
3143
+ {
3144
+ style: {
3145
+ width: 24,
3146
+ height: 24,
3147
+ borderRadius: "50%",
3148
+ background: t.bg,
3149
+ display: "flex",
3150
+ alignItems: "center",
3151
+ justifyContent: "center",
3152
+ fontSize: 11,
3153
+ fontWeight: 700,
3154
+ color: "#fff",
3155
+ marginLeft: i > 0 ? -4 : 0,
3156
+ border: `2px solid ${colors.card}`,
3157
+ boxSizing: "content-box"
3158
+ },
3159
+ children: t.label
3160
+ },
3161
+ i
3162
+ )) });
3163
+ };
3164
+ function chainsToTokenOptions(chains) {
3165
+ const bySymbol = /* @__PURE__ */ new Map();
3166
+ for (const c of chains) {
3167
+ for (const t of c.tokens) {
3168
+ if (!bySymbol.has(t.symbol)) bySymbol.set(t.symbol, { symbol: t.symbol, decimals: t.decimals });
3169
+ }
3170
+ }
3171
+ return Array.from(bySymbol.entries()).map(([id, { symbol }]) => ({
3172
+ id,
3173
+ label: symbol,
3174
+ subtitle: symbol
3175
+ }));
3176
+ }
3177
+ function chainsToChainOptionsForToken(chains, tokenSymbol) {
3178
+ return chains.filter((c) => c.tokens.some((t) => t.symbol === tokenSymbol)).map((c) => ({
3179
+ id: c.chain_id,
3180
+ label: c.network,
3181
+ subtitle: `chainId: ${c.chain_id}`,
3182
+ icon: /* @__PURE__ */ jsx(
3183
+ "span",
3184
+ {
3185
+ style: {
3186
+ display: "inline-flex",
3187
+ alignItems: "center",
3188
+ justifyContent: "center",
3189
+ minWidth: 28,
3190
+ height: 28,
3191
+ padding: "0 6px",
3192
+ borderRadius: radii.card,
3193
+ background: "rgba(255,255,255,0.08)",
3194
+ fontSize: 12,
3195
+ fontWeight: 600,
3196
+ color: colors.textPrimary,
3197
+ fontFamily: fonts.family
3198
+ },
3199
+ children: c.network
3200
+ }
3201
+ )
3202
+ }));
3203
+ }
3204
+ function getTokenAddressForChain(chains, chainId, tokenSymbol) {
3205
+ const chain = chains.find((c) => c.chain_id === chainId);
3206
+ return chain?.tokens.find((t) => t.symbol === tokenSymbol)?.address;
3207
+ }
3208
+ var FUNDING_TOKEN_SYMBOL = getEnv("FUNDING_TOKEN_SYMBOL");
3209
+ var DepositModal = ({
3210
+ token,
3211
+ chain,
3212
+ tokenOptions: tokenOptionsProp,
3213
+ chainOptions: chainOptionsProp,
3214
+ depositAddress,
3215
+ minimumDeposit,
3216
+ qrCenterIcon,
3217
+ cryptoIcons,
3218
+ depositAmount,
3219
+ onShowToast,
3220
+ txHash,
3221
+ explorerTxUrl,
3222
+ onTokenSelect,
3223
+ onChainSelect,
3224
+ onCopyAddress,
3225
+ onBuyCrypto,
3226
+ onSignIn,
3227
+ onBack,
3228
+ onClose
3229
+ }) => {
3230
+ const session = useSession();
3231
+ const [view, setView] = useState("entry");
3232
+ const [copySuccessMessage, setCopySuccessMessage] = useState(null);
3233
+ const [apiChains, setApiChains] = useState(null);
3234
+ const [apiQuote, setApiQuote] = useState(null);
3235
+ const [loadingChains, setLoadingChains] = useState(false);
3236
+ const [loadingQuote, setLoadingQuote] = useState(false);
3237
+ const [quoteRefreshKey, setQuoteRefreshKey] = useState(0);
3238
+ const [internalDepositAddress, setInternalDepositAddress] = useState(void 0);
3239
+ const lastEmittedAddressRef = useRef(void 0);
3240
+ const lastEmittedChainRef = useRef(void 0);
3241
+ const tokenOptions = useMemo(() => {
3242
+ if (tokenOptionsProp?.length) return tokenOptionsProp;
3243
+ if (!apiChains?.length) return void 0;
3244
+ return chainsToTokenOptions(apiChains);
3245
+ }, [tokenOptionsProp, apiChains]);
3246
+ const chainOptions = useMemo(() => {
3247
+ if (chainOptionsProp?.length) return chainOptionsProp;
3248
+ if (!apiChains?.length || !token) return void 0;
3249
+ return chainsToChainOptionsForToken(apiChains, token);
3250
+ }, [chainOptionsProp, apiChains, token]);
3251
+ useEffect(() => {
3252
+ if (chainOptions?.length !== 1 || !onChainSelect) return;
3253
+ const onlyId = chainOptions[0].id;
3254
+ if (chain === onlyId) return;
3255
+ onChainSelect(onlyId);
3256
+ }, [chainOptions, chain, onChainSelect]);
3257
+ useEffect(() => {
3258
+ if (view !== "transfer") return;
3259
+ setLoadingChains(true);
3260
+ getChains().then((res) => setApiChains(res?.chains ?? {})).finally(() => setLoadingChains(false));
3261
+ }, [view]);
3262
+ useEffect(() => {
3263
+ if (view !== "transfer") return;
3264
+ if (!session?.address || !chain) return;
3265
+ registerPlatform({
3266
+ platform_contract_address: session.address,
3267
+ chain_id: chain
3268
+ }).then((res) => {
3269
+ if (res?.deposit_address) {
3270
+ setInternalDepositAddress(res.deposit_address);
3271
+ }
3272
+ }).catch(() => {
3273
+ });
3274
+ }, [view, chain, session?.address]);
3275
+ useEffect(() => {
3276
+ if (!apiChains?.length || !token || !chain) {
3277
+ setApiQuote(null);
3278
+ return;
3279
+ }
3280
+ const tokenAddress = getTokenAddressForChain(apiChains, chain, token);
3281
+ if (!tokenAddress) {
3282
+ setApiQuote(null);
3283
+ return;
3284
+ }
3285
+ setLoadingQuote(true);
3286
+ console.log("setLoadingQuote", tokenAddress, depositAmount);
3287
+ quote({
3288
+ direction: "deposit",
3289
+ chain_id: chain,
3290
+ token_address: tokenAddress,
3291
+ token_amount: depositAmount || void 0
3292
+ }).then((q) => setApiQuote(q ?? null)).catch((err) => {
3293
+ const message = err?.message ?? String(err);
3294
+ console.error("setLoadingQuote", message);
3295
+ if (onShowToast) onShowToast(message);
3296
+ setApiQuote({
3297
+ token_address: tokenAddress,
3298
+ token_symbol: token,
3299
+ token_decimals: 18,
3300
+ rate: "1",
3301
+ chain_id: Number(chain) || 56,
3302
+ deposit_address: "0x" + "0".repeat(39) + "1",
3303
+ dst_token_amount: depositAmount ?? "0",
3304
+ expires_at: new Date(Date.now() + 6e4).toISOString()
3305
+ });
3306
+ }).finally(() => setLoadingQuote(false));
3307
+ }, [apiChains, token, chain, depositAmount, quoteRefreshKey, onShowToast]);
3308
+ useEffect(() => {
3309
+ if (!chain) return;
3310
+ if (!depositAddress) return;
3311
+ if (lastEmittedAddressRef.current === depositAddress && lastEmittedChainRef.current === chain) {
3312
+ return;
3313
+ }
3314
+ lastEmittedAddressRef.current = depositAddress;
3315
+ lastEmittedChainRef.current = chain;
3316
+ }, [depositAddress, chain]);
3317
+ const handleQuoteExpired = useCallback(() => {
3318
+ setQuoteRefreshKey((k) => k + 1);
3319
+ }, []);
3320
+ useEffect(() => {
3321
+ if (txHash && chain && onShowToast) {
3322
+ onShowToast("Transfer confirmed");
3323
+ }
3324
+ }, [txHash, chain, onShowToast]);
3325
+ if (!session) {
3326
+ return /* @__PURE__ */ jsx(LoginRequiredOverlay, { title: "Deposit", onSignIn, onClose });
3327
+ }
3328
+ const goToEntry = () => {
3329
+ setView("entry");
3330
+ onBack?.();
3331
+ };
3332
+ const handleCopyAddress = useCallback((address) => {
3333
+ onCopyAddress?.(address);
3334
+ onShowToast?.("Address copied");
3335
+ setCopySuccessMessage("Address copied");
3336
+ }, [onCopyAddress, onShowToast]);
3337
+ useEffect(() => {
3338
+ if (!copySuccessMessage) return;
3339
+ const t = setTimeout(() => setCopySuccessMessage(null), 2e3);
3340
+ return () => clearTimeout(t);
3341
+ }, [copySuccessMessage]);
3342
+ return /* @__PURE__ */ jsxs(ModalFrame, { onClose, contentStyle: { padding: "24px", position: "relative" }, children: [
3343
+ copySuccessMessage && /* @__PURE__ */ jsx(
3344
+ "div",
3345
+ {
3346
+ style: {
3347
+ position: "absolute",
3348
+ bottom: 24,
3349
+ left: "50%",
3350
+ transform: "translateX(-50%)",
3351
+ padding: "10px 20px",
3352
+ borderRadius: 8,
3353
+ background: "var(--pm-colors-card, #1a1a2e)",
3354
+ color: "var(--pm-colors-textPrimary, #fff)",
3355
+ fontSize: 13,
3356
+ fontWeight: 500,
3357
+ boxShadow: "0 4px 12px rgba(0,0,0,.25)",
3358
+ zIndex: 10
3359
+ },
3360
+ children: copySuccessMessage
3361
+ }
3362
+ ),
3363
+ view === "entry" ? /* @__PURE__ */ jsx(
3364
+ EntryView,
3365
+ {
3366
+ cryptoIcons,
3367
+ onTransferCrypto: () => setView("transfer"),
3368
+ onBuyCrypto
3369
+ }
3370
+ ) : /* @__PURE__ */ jsx(
3371
+ TransferView,
3372
+ {
3373
+ token,
3374
+ chain,
3375
+ tokenOptions,
3376
+ chainOptions,
3377
+ depositAddress: depositAddress ?? internalDepositAddress,
3378
+ minimumDeposit,
3379
+ qrCenterIcon,
3380
+ quote: apiQuote,
3381
+ quoteLoading: loadingQuote,
3382
+ txHash,
3383
+ chainIdForExplorer: chain,
3384
+ explorerTxUrl,
3385
+ loadingChains,
3386
+ onTokenSelect,
3387
+ onChainSelect,
3388
+ onCopyAddress: handleCopyAddress,
3389
+ onQuoteExpired: handleQuoteExpired,
3390
+ onRefreshQuote: () => {
3391
+ if (!apiChains?.length || !token || !chain) return;
3392
+ const tokenAddress = getTokenAddressForChain(apiChains, chain, token);
3393
+ if (tokenAddress) {
3394
+ setLoadingQuote(true);
3395
+ quote({ direction: "deposit", chain_id: chain, token_address: tokenAddress, token_amount: depositAmount }).then((q) => setApiQuote(q ?? null)).catch(() => {
3396
+ setApiQuote({
3397
+ token_address: tokenAddress,
3398
+ token_symbol: token,
3399
+ token_decimals: 18,
3400
+ rate: "1",
3401
+ chain_id: Number(chain) || 56,
3402
+ deposit_address: "0x" + "0".repeat(39) + "1",
3403
+ dst_token_amount: depositAmount ?? "0",
3404
+ expires_at: new Date(Date.now() + 6e4).toISOString()
3405
+ });
3406
+ }).finally(() => setLoadingQuote(false));
3407
+ }
3408
+ },
3409
+ onShowToast,
3410
+ onBack: goToEntry
3411
+ }
3412
+ )
3413
+ ] });
3414
+ };
3415
+ var EntryView = ({
3416
+ cryptoIcons,
3417
+ onTransferCrypto,
3418
+ onBuyCrypto: _onBuyCrypto
3419
+ }) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 24 }, children: [
3420
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: 24, fontWeight: 600, lineHeight: 1.4 }, children: "Deposit" }),
3421
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
3422
+ /* @__PURE__ */ jsxs(
3423
+ "button",
3424
+ {
3425
+ type: "button",
3426
+ onClick: onTransferCrypto,
3427
+ style: {
3428
+ display: "flex",
3429
+ alignItems: "center",
3430
+ gap: 14,
3431
+ padding: "18px 20px",
3432
+ borderRadius: radii.card,
3433
+ border: `1px solid ${colors.border}`,
3434
+ background: "transparent",
3435
+ cursor: "pointer",
3436
+ textAlign: "left",
3437
+ fontFamily: fonts.family,
3438
+ width: "100%",
3439
+ transition: "border-color .15s"
3440
+ },
3441
+ onMouseEnter: (e) => {
3442
+ e.target.closest("button").style.borderColor = colors.borderStrong;
3443
+ },
3444
+ onMouseLeave: (e) => {
3445
+ e.target.closest("button").style.borderColor = colors.border;
3446
+ },
3447
+ children: [
3448
+ /* @__PURE__ */ jsx(TransferIcon, {}),
3449
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", gap: 2 }, children: [
3450
+ /* @__PURE__ */ jsx("span", { style: { color: colors.textPrimary, fontSize: 16, fontWeight: 600 }, children: "Transfer Crypto" }),
3451
+ /* @__PURE__ */ jsx("span", { style: { color: colors.textSecondary, fontSize: 13 }, children: "No limit \xB7 Instant" })
3452
+ ] }),
3453
+ cryptoIcons ?? /* @__PURE__ */ jsx(DefaultCryptoIcons, {})
3454
+ ]
3455
+ }
3456
+ ),
3457
+ /* @__PURE__ */ jsxs(
3458
+ "div",
3459
+ {
3460
+ style: {
3461
+ display: "flex",
3462
+ alignItems: "center",
3463
+ gap: 14,
3464
+ padding: "18px 20px",
3465
+ borderRadius: radii.card,
3466
+ border: `1px solid ${colors.border}`,
3467
+ opacity: 0.55
3468
+ },
3469
+ children: [
3470
+ /* @__PURE__ */ jsx(FiatIcon, {}),
3471
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", gap: 2 }, children: [
3472
+ /* @__PURE__ */ jsx("span", { style: { color: colors.textSecondary, fontSize: 16, fontWeight: 600 }, children: "Buy Crypto" }),
3473
+ /* @__PURE__ */ jsx("span", { style: { color: colors.textSecondary, fontSize: 13 }, children: "Debit card, credit card, ACH" })
3474
+ ] }),
3475
+ /* @__PURE__ */ jsx(
3476
+ "span",
3477
+ {
3478
+ style: {
3479
+ padding: "5px 12px",
3480
+ borderRadius: radii.pill,
3481
+ border: `1px solid ${colors.border}`,
3482
+ fontSize: 12,
3483
+ fontWeight: 500,
3484
+ color: colors.textSecondary,
3485
+ whiteSpace: "nowrap"
3486
+ },
3487
+ children: "Coming Soon"
3488
+ }
3489
+ )
3490
+ ]
3491
+ }
3492
+ )
3493
+ ] })
3494
+ ] });
3495
+ var TransferView = ({
3496
+ token,
3497
+ chain,
3498
+ tokenOptions,
3499
+ chainOptions,
3500
+ depositAddress,
3501
+ minimumDeposit,
3502
+ qrCenterIcon,
3503
+ quote: quoteData,
3504
+ quoteLoading,
3505
+ txHash,
3506
+ chainIdForExplorer,
3507
+ explorerTxUrl,
3508
+ loadingChains,
3509
+ onTokenSelect,
3510
+ onChainSelect,
3511
+ onCopyAddress,
3512
+ onQuoteExpired,
3513
+ onRefreshQuote,
3514
+ onShowToast,
3515
+ onBack
3516
+ }) => {
3517
+ const activeStep = chain ? 2 : token ? 1 : 0;
3518
+ const stepActive = [!!token, !!chain, !!quoteData];
3519
+ const quoteExpired = useMemo(() => {
3520
+ if (!quoteData?.expires_at) return false;
3521
+ try {
3522
+ return new Date(quoteData.expires_at).getTime() < Date.now();
3523
+ } catch {
3524
+ return false;
3525
+ }
3526
+ }, [quoteData?.expires_at]);
3527
+ const didToastWait = useRef(false);
3528
+ useEffect(() => {
3529
+ if (!depositAddress || !onShowToast || didToastWait.current) return;
3530
+ didToastWait.current = true;
3531
+ onShowToast("Please wait for deposit-address balance to update");
3532
+ }, [depositAddress, onShowToast]);
3533
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 24 }, children: [
3534
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
3535
+ onBack && /* @__PURE__ */ jsx(
3536
+ "button",
3537
+ {
3538
+ type: "button",
3539
+ onClick: onBack,
3540
+ style: {
3541
+ background: "transparent",
3542
+ border: "none",
3543
+ cursor: "pointer",
3544
+ padding: 0,
3545
+ display: "flex",
3546
+ alignItems: "center"
3547
+ },
3548
+ children: /* @__PURE__ */ jsx(BackArrow, {})
3549
+ }
3550
+ ),
3551
+ /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: 24, fontWeight: 600, lineHeight: 1.4 }, children: "Transfer Crypto" })
3552
+ ] }) }),
3553
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 16, position: "relative" }, children: [
3554
+ /* @__PURE__ */ jsx(StepIndicator, { steps: 3, stepActive, activeStep }),
3555
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", gap: 40 }, children: [
3556
+ /* @__PURE__ */ jsx(
3557
+ DropdownField,
3558
+ {
3559
+ label: "Select token",
3560
+ placeholder: loadingChains ? "Loading\u2026" : "Token",
3561
+ value: token,
3562
+ options: tokenOptions,
3563
+ onSelect: onTokenSelect
3564
+ }
3565
+ ),
3566
+ /* @__PURE__ */ jsx(
3567
+ DropdownField,
3568
+ {
3569
+ label: "Select chain",
3570
+ placeholder: loadingChains ? "Loading\u2026" : "Chain",
3571
+ value: chain,
3572
+ options: chainOptions,
3573
+ onSelect: onChainSelect
3574
+ }
3575
+ ),
3576
+ quoteData && token && chain && /* @__PURE__ */ jsx(
3577
+ "div",
3578
+ {
3579
+ id: "quote-panel",
3580
+ style: {
3581
+ padding: "12px 16px",
3582
+ borderRadius: radii.card,
3583
+ margin: "-10px 0",
3584
+ border: `1px solid ${colors.border}`,
3585
+ display: "flex",
3586
+ flexDirection: "column",
3587
+ gap: 8
3588
+ },
3589
+ children: quoteLoading ? /* @__PURE__ */ jsx("span", { style: { fontSize: 13, color: colors.textSecondary }, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3590
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: 13, color: colors.textSecondary }, children: [
3591
+ "1 ",
3592
+ quoteData.token_symbol,
3593
+ " = ",
3594
+ quoteData.rate,
3595
+ " ",
3596
+ FUNDING_TOKEN_SYMBOL
3597
+ ] }),
3598
+ quoteData.expires_at && /* @__PURE__ */ jsx(
3599
+ Countdown,
3600
+ {
3601
+ expiresAt: quoteData.expires_at,
3602
+ isExpired: quoteExpired,
3603
+ onExpired: onQuoteExpired
3604
+ }
3605
+ ),
3606
+ quoteExpired && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
3607
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 13, color: "#f59e0b" }, children: "Quote expired, please refresh" }),
3608
+ onRefreshQuote && /* @__PURE__ */ jsx(
3609
+ "button",
3610
+ {
3611
+ type: "button",
3612
+ onClick: onRefreshQuote,
3613
+ style: {
3614
+ padding: "4px 12px",
3615
+ fontSize: 12,
3616
+ borderRadius: radii.pill,
3617
+ border: `1px solid ${colors.border}`,
3618
+ background: "transparent",
3619
+ color: colors.textPrimary,
3620
+ cursor: "pointer",
3621
+ fontFamily: fonts.family
3622
+ },
3623
+ children: "Refresh"
3624
+ }
3625
+ )
3626
+ ] })
3627
+ ] })
3628
+ }
3629
+ ),
3630
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8, marginTop: "-5px" }, id: "deposit-details", children: [
3631
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textPrimary }, children: "Deposit details" }),
3632
+ depositAddress ? /* @__PURE__ */ jsxs(Fragment, { children: [
3633
+ /* @__PURE__ */ jsx(
3634
+ DepositDetailsPanel,
3635
+ {
3636
+ address: depositAddress,
3637
+ tokenIcon: qrCenterIcon,
3638
+ minimumDeposit,
3639
+ onCopyAddress
3640
+ }
3641
+ ),
3642
+ txHash && chainIdForExplorer && explorerTxUrl && /* @__PURE__ */ jsx(
3643
+ "a",
3644
+ {
3645
+ href: explorerTxUrl(chainIdForExplorer, txHash),
3646
+ target: "_blank",
3647
+ rel: "noopener noreferrer",
3648
+ style: {
3649
+ fontSize: 13,
3650
+ color: colors.textPrimary,
3651
+ textDecoration: "underline"
3652
+ },
3653
+ children: "View on explorer"
3654
+ }
3655
+ )
3656
+ ] }) : /* @__PURE__ */ jsx(
3657
+ "div",
3658
+ {
3659
+ style: {
3660
+ padding: "20px",
3661
+ borderRadius: radii.card,
3662
+ border: `1px solid ${colors.border}`,
3663
+ color: colors.textSecondary,
3664
+ fontSize: 13,
3665
+ textAlign: "center"
3666
+ },
3667
+ children: "Select token and chain to view deposit details"
3668
+ }
3669
+ )
3670
+ ] })
3671
+ ] })
3672
+ ] })
3673
+ ] });
3674
+ };
3675
+
3676
+ // src/utils/explorer.ts
3677
+ var explorerTemplates = {
3678
+ "0": "",
3679
+ "1": "https://etherscan.io/tx/{txId}",
3680
+ "3": "https://dogechain.info/tx/{txId}",
3681
+ "10": "https://optimistic.etherscan.io/tx/{txId}",
3682
+ "56": "https://bscscan.com/tx/{txId}",
3683
+ "110": "",
3684
+ "126": "https://explorer.movementnetwork.xyz/txn/{txId}?network=mainnet",
3685
+ "137": "https://polygonscan.com/tx/{txId}",
3686
+ "204": "https://opbnb.bscscan.com/tx/{txId}",
3687
+ "223": "https://explorer.bsquared.network/tx/{txId}",
3688
+ "227": "https://promscan.io/tx/{txId}",
3689
+ "324": "https://mainnet.era.zksync.io/tx/{txId}",
3690
+ "400": "",
3691
+ "420": "https://scan.merlinchain.io/tx/{txId}",
3692
+ "480": "https://worldchain-mainnet.explorer.alchemy.com/tx/{txId}",
3693
+ "501": "https://solscan.io/tx/{txId}",
3694
+ "784": "",
3695
+ "1329": "https://seitrace.com/tx/{txId}",
3696
+ "1514": "https://mainnet.storyscan.xyz/tx/{txId}",
3697
+ "1625": "https://explorer.gravity.xyz/tx/{txId}",
3698
+ "2649": "https://mainnet-explorer.ailayer.xyz/tx/{txId}",
3699
+ "3030": "https://dashboard.tenderly.co/explorer/vnet/bd8df763-9888-4be3-9a78-26f1d5ab8d3d/tx/{txId}",
3700
+ "3131": "https://dashboard.tenderly.co/explorer/vnet/6593bc72-f548-497d-bff9-5be061436a48/tx/{txId}",
3701
+ "5545": "https://scan.duckchain.io/tx/{txId}",
3702
+ "8333": "https://mainnet-rpc.b3.fun/http/tx/{txId}",
3703
+ "8453": "https://base.blockscout.com/tx/{txId}",
3704
+ "19484": "https://tronscan.org/#/transaction/{txId}",
3705
+ "21000": "https://maizenet-explorer.usecorn.com/tx/{txId}",
3706
+ "42161": "https://arbiscan.io/tx/{txId}",
3707
+ "43114": "https://snowtrace.io/tx/{txId}",
3708
+ "47763": "https://neotube.io/transaction/{txId}",
3709
+ "59144": "https://lineascan.build/tx/{txId}",
3710
+ "60808": "https://rpc.gobob.xyz/tx/{txId}",
3711
+ "80094": "https://berascan.com/tx/{txId}",
3712
+ "81457": "https://blastscan.io/tx/{txId}",
3713
+ "200901": "https://rpc.bitlayer.org/tx/{txId}",
3714
+ "221122420": "https://blockscout.devnet.doge.xyz/tx/{txId}",
3715
+ "534352": "https://scrollscan.com/tx/{txId}"
3716
+ };
3717
+ function getExplorerUrl(chainId, data) {
3718
+ const template = explorerTemplates[chainId] ?? "";
3719
+ if (template === "") {
3720
+ throw new Error(`chainId ${chainId} tpl not found`);
3721
+ }
3722
+ return template.replace("{txId}", data.txId);
3723
+ }
3724
+ var SuccessIcon = () => {
3725
+ return /* @__PURE__ */ jsxs("svg", { width: "80", height: "81", viewBox: "0 0 80 81", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
3726
+ /* @__PURE__ */ jsx(
3727
+ "path",
3728
+ {
3729
+ d: "M40 80.5C62.0914 80.5 80 62.5914 80 40.5C80 18.4086 62.0914 0.5 40 0.5C17.9086 0.5 0 18.4086 0 40.5C0 62.5914 17.9086 80.5 40 80.5Z",
3730
+ fill: "#627EEA"
3731
+ }
3732
+ ),
3733
+ /* @__PURE__ */ jsx(
3734
+ "path",
3735
+ {
3736
+ d: "M38.999 16.5V34.2437L53.9962 40.9451L38.999 16.5Z",
3737
+ fill: "white",
3738
+ fillOpacity: "0.602"
3739
+ }
3740
+ ),
3741
+ /* @__PURE__ */ jsx("path", { d: "M38.9991 16.5L24 40.9451L38.9991 34.2437V16.5Z", fill: "white" }),
3742
+ /* @__PURE__ */ jsx(
3743
+ "path",
3744
+ {
3745
+ d: "M38.999 52.4434V64.4999L54.0061 43.7376L38.999 52.4434Z",
3746
+ fill: "white",
3747
+ fillOpacity: "0.602"
3748
+ }
3749
+ ),
3750
+ /* @__PURE__ */ jsx("path", { d: "M38.9991 64.4999V52.4414L24 43.7376L38.9991 64.4999Z", fill: "white" }),
3751
+ /* @__PURE__ */ jsx(
3752
+ "path",
3753
+ {
3754
+ d: "M38.999 49.653L53.9962 40.9451L38.999 34.2477V49.653Z",
3755
+ fill: "white",
3756
+ fillOpacity: "0.2"
3757
+ }
3758
+ ),
3759
+ /* @__PURE__ */ jsx(
3760
+ "path",
3761
+ {
3762
+ d: "M24 40.9451L38.9991 49.653V34.2477L24 40.9451Z",
3763
+ fill: "white",
3764
+ fillOpacity: "0.602"
3765
+ }
3766
+ ),
3767
+ /* @__PURE__ */ jsx("g", { filter: "url(#filter0_ii_34_1690)", children: /* @__PURE__ */ jsx("circle", { cx: "40", cy: "40", r: "40", fill: "url(#paint0_linear_34_1690)" }) }),
3768
+ /* @__PURE__ */ jsx(
3769
+ "path",
3770
+ {
3771
+ d: "M25.8057 35.9858L38.7921 49.0324L56.7734 30.9678",
3772
+ stroke: "#58AE36",
3773
+ strokeWidth: "5.16129",
3774
+ fill: "none"
3775
+ }
3776
+ ),
3777
+ /* @__PURE__ */ jsxs("defs", { children: [
3778
+ /* @__PURE__ */ jsxs(
3779
+ "filter",
3780
+ {
3781
+ id: "filter0_ii_34_1690",
3782
+ x: "0",
3783
+ y: "0",
3784
+ width: "80",
3785
+ height: "80",
3786
+ filterUnits: "userSpaceOnUse",
3787
+ colorInterpolationFilters: "sRGB",
3788
+ children: [
3789
+ /* @__PURE__ */ jsx("feFlood", { floodOpacity: "0", result: "BackgroundImageFix" }),
3790
+ /* @__PURE__ */ jsx("feBlend", { mode: "normal", in: "SourceGraphic", in2: "BackgroundImageFix", result: "shape" }),
3791
+ /* @__PURE__ */ jsx(
3792
+ "feColorMatrix",
3793
+ {
3794
+ in: "SourceAlpha",
3795
+ type: "matrix",
3796
+ values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
3797
+ result: "hardAlpha"
3798
+ }
3799
+ ),
3800
+ /* @__PURE__ */ jsx("feOffset", { dx: "-1.29032", dy: "-1.29032" }),
3801
+ /* @__PURE__ */ jsx("feComposite", { in2: "hardAlpha", operator: "arithmetic", k2: "-1", k3: "1" }),
3802
+ /* @__PURE__ */ jsx(
3803
+ "feColorMatrix",
3804
+ {
3805
+ type: "matrix",
3806
+ values: "0 0 0 0 0.584745 0 0 0 0 1 0 0 0 0 0.420982 0 0 0 1 0"
3807
+ }
3808
+ ),
3809
+ /* @__PURE__ */ jsx("feBlend", { mode: "multiply", in2: "shape", result: "effect1_innerShadow_34_1690" }),
3810
+ /* @__PURE__ */ jsx(
3811
+ "feColorMatrix",
3812
+ {
3813
+ in: "SourceAlpha",
3814
+ type: "matrix",
3815
+ values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
3816
+ result: "hardAlpha"
3817
+ }
3818
+ ),
3819
+ /* @__PURE__ */ jsx("feOffset", { dx: "1.29032", dy: "1.29032" }),
3820
+ /* @__PURE__ */ jsx("feComposite", { in2: "hardAlpha", operator: "arithmetic", k2: "-1", k3: "1" }),
3821
+ /* @__PURE__ */ jsx("feColorMatrix", { type: "matrix", values: "0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0" }),
3822
+ /* @__PURE__ */ jsx("feBlend", { mode: "normal", in2: "effect1_innerShadow_34_1690", result: "effect2_innerShadow_34_1690" })
3823
+ ]
3824
+ }
3825
+ ),
3826
+ /* @__PURE__ */ jsxs(
3827
+ "linearGradient",
3828
+ {
3829
+ id: "paint0_linear_34_1690",
3830
+ x1: "27.4722",
3831
+ y1: "7.62951",
3832
+ x2: "70.4313",
3833
+ y2: "26.563",
3834
+ gradientUnits: "userSpaceOnUse",
3835
+ children: [
3836
+ /* @__PURE__ */ jsx("stop", { stopColor: "#BBFFA1" }),
3837
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#ACFE8B" })
3838
+ ]
3839
+ }
3840
+ )
3841
+ ] })
3842
+ ] });
3843
+ };
3844
+ function CopyIcon2() {
3845
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true, children: [
3846
+ /* @__PURE__ */ jsx("rect", { x: "5", y: "5", width: "9", height: "9", rx: "1", stroke: "currentColor", strokeWidth: "1.2", fill: "none" }),
3847
+ /* @__PURE__ */ jsx("path", { d: "M3 11V3a1 1 0 0 1 1-1h8", stroke: "currentColor", strokeWidth: "1.2", fill: "none" })
3848
+ ] });
3849
+ }
3850
+ var FUNDING_TOKEN_SYMBOL2 = getEnv("FUNDING_TOKEN_SYMBOL");
3851
+ function chainsToTokenOptions2(chains) {
3852
+ const bySymbol = /* @__PURE__ */ new Map();
3853
+ for (const c of chains) {
3854
+ for (const t of c.tokens) {
3855
+ if (!bySymbol.has(t.symbol)) bySymbol.set(t.symbol, t.symbol);
3856
+ }
3857
+ }
3858
+ return Array.from(bySymbol.entries()).map(([id, symbol]) => ({
3859
+ id,
3860
+ label: symbol,
3861
+ subtitle: symbol
3862
+ }));
3863
+ }
3864
+ function chainsToChainOptionsForToken2(chains, tokenSymbol) {
3865
+ return chains.filter((c) => c.tokens.some((t) => t.symbol === tokenSymbol)).map((c) => ({ id: c.chain_id, label: c.network, subtitle: c.chain_id }));
3866
+ }
3867
+ function getTokenAddressForChain2(chains, chainId, tokenSymbol) {
3868
+ const chain = chains.find((c) => c.chain_id === chainId);
3869
+ return chain?.tokens.find((t) => t.symbol === tokenSymbol)?.address;
3870
+ }
3871
+ function parseBalanceNumber(balance) {
3872
+ const match = balance.trim().match(/^(\d*\.?\d*)/);
3873
+ if (!match) return null;
3874
+ const n = Number(match[1]);
3875
+ return Number.isNaN(n) ? null : n;
3876
+ }
3877
+ function formatBalanceTo2Decimals(balance) {
3878
+ const match = balance.trim().match(/^(\d*\.?\d*)(.*)$/);
3879
+ if (!match) return balance;
3880
+ const numPart = match[1];
3881
+ const suffix = match[2].trim() ? " " + match[2].trim() : "";
3882
+ const n = Number(numPart);
3883
+ if (Number.isNaN(n)) return balance;
3884
+ const formatted = n.toFixed(2);
3885
+ return formatted + suffix;
3886
+ }
3887
+ function weiToEtherDisplay(wei) {
3888
+ const s = (wei || "0").trim().replace(/^0+/, "") || "0";
3889
+ if (s === "0") return "0";
3890
+ const padded = s.padStart(19, "0");
3891
+ const intPart = padded.slice(0, Math.max(0, padded.length - 18));
3892
+ const decPart = padded.slice(-18).replace(/0+$/, "");
3893
+ const combined = decPart ? `${intPart}.${decPart}` : intPart;
3894
+ const num = Number(combined);
3895
+ if (Number.isNaN(num)) return wei;
3896
+ const fixed = num.toFixed(6).replace(/\.?0+$/, "");
3897
+ return fixed;
3898
+ }
3899
+ var POLL_INTERVAL_MS = 4e3;
3900
+ var WithdrawModal = ({
3901
+ address = "",
3902
+ token,
3903
+ tokenSymbol,
3904
+ chain,
3905
+ amount = "",
3906
+ balance,
3907
+ status = "idle",
3908
+ receiveAmount: receiveAmountProp,
3909
+ txHash,
3910
+ tokenOptions: tokenOptionsProp,
3911
+ chainOptions: chainOptionsProp,
3912
+ useMerchantApi = false,
3913
+ orderId,
3914
+ withdrawMode,
3915
+ withdrawDirectResult,
3916
+ feeDisplay,
3917
+ fundingChainId,
3918
+ onShowToast,
3919
+ onAddressChange,
3920
+ onTokenSelect,
3921
+ onChainSelect,
3922
+ onAmountChange,
3923
+ onMaxClick,
3924
+ onSubmit,
3925
+ onWithdrawCompleted,
3926
+ onStartAnotherWithdrawal,
3927
+ onSignIn,
3928
+ onClose
3929
+ }) => {
3930
+ const session = useSession();
3931
+ const addressInputRef = useRef(null);
3932
+ const [addressInputFocused, setAddressInputFocused] = useState(false);
3933
+ const [amountInputFocused, setAmountInputFocused] = useState(false);
3934
+ const [apiChains, setApiChains] = useState(null);
3935
+ const [apiQuote, setApiQuote] = useState(null);
3936
+ const [withdrawOrder, setWithdrawOrder] = useState(null);
3937
+ const [loadingChains, setLoadingChains] = useState(false);
3938
+ const [loadingQuote, setLoadingQuote] = useState(false);
3939
+ const tokenOptions = useMemo(() => {
3940
+ const raw = tokenOptionsProp?.length ? tokenOptionsProp : apiChains?.length ? chainsToTokenOptions2(apiChains) : void 0;
3941
+ if (!raw?.length) return void 0;
3942
+ return raw;
3943
+ }, [tokenOptionsProp, apiChains]);
3944
+ const chainOptions = useMemo(() => {
3945
+ if (chainOptionsProp?.length) return chainOptionsProp;
3946
+ if (!apiChains?.length || !token) return void 0;
3947
+ return chainsToChainOptionsForToken2(apiChains, token);
3948
+ }, [chainOptionsProp, apiChains, token]);
3949
+ const resolvedTokenAddress = useMemo(() => {
3950
+ if (!apiChains?.length || !token || !chain) return void 0;
3951
+ return getTokenAddressForChain2(apiChains, chain, token);
3952
+ }, [apiChains, token, chain]);
3953
+ const [directActive, setDirectActive] = useState(false);
3954
+ useEffect(() => {
3955
+ setDirectActive(withdrawMode === "direct" && Boolean(withdrawDirectResult));
3956
+ }, [withdrawMode, withdrawDirectResult]);
3957
+ const trackingWithdraw = useMemo(
3958
+ () => Boolean(orderId) || directActive,
3959
+ [orderId, directActive]
3960
+ );
3961
+ useEffect(() => {
3962
+ if (trackingWithdraw) return;
3963
+ const t = requestAnimationFrame(() => {
3964
+ addressInputRef.current?.focus();
3965
+ });
3966
+ return () => cancelAnimationFrame(t);
3967
+ }, [trackingWithdraw]);
3968
+ const shouldLoadChains = useMerchantApi || Boolean(token && chain);
3969
+ useEffect(() => {
3970
+ if (!shouldLoadChains) return;
3971
+ setLoadingChains(true);
3972
+ getChains().then((res) => setApiChains(res?.chains ?? [])).finally(() => setLoadingChains(false));
3973
+ }, [shouldLoadChains]);
3974
+ useEffect(() => {
3975
+ if (!apiChains?.length || !token || !chain) {
3976
+ setApiQuote(null);
3977
+ return;
3978
+ }
3979
+ const tokenAddress = getTokenAddressForChain2(apiChains, chain, token);
3980
+ if (!tokenAddress) {
3981
+ setApiQuote(null);
3982
+ return;
3983
+ }
3984
+ const amountNum = amount && Number(amount) > 0 ? Number(amount) : 1;
3985
+ const amountWei = String(BigInt(Math.floor(amountNum * 1e18)));
3986
+ setLoadingQuote(true);
3987
+ quote({
3988
+ direction: "withdraw",
3989
+ chain_id: chain,
3990
+ token_address: tokenAddress,
3991
+ dst_token_amount: amountWei
3992
+ }).then((q) => setApiQuote(q ?? null)).catch(() => {
3993
+ setApiQuote({
3994
+ token_address: tokenAddress,
3995
+ token_symbol: token,
3996
+ token_decimals: 18,
3997
+ rate: "1",
3998
+ chain_id: Number(chain) || 56,
3999
+ token_amount: amountWei,
4000
+ expires_at: new Date(Date.now() + 6e4).toISOString()
4001
+ });
4002
+ }).finally(() => setLoadingQuote(false));
4003
+ }, [apiChains, token, chain, amount]);
4004
+ useEffect(() => {
4005
+ if (tokenOptions?.length !== 1 || !onTokenSelect) return;
4006
+ const onlyId = tokenOptions[0].id;
4007
+ if (token === onlyId) return;
4008
+ onTokenSelect(onlyId);
4009
+ }, [tokenOptions, token, onTokenSelect]);
4010
+ useEffect(() => {
4011
+ if (chainOptions?.length !== 1 || !onChainSelect) return;
4012
+ const onlyId = chainOptions[0].id;
4013
+ if (chain === onlyId) return;
4014
+ onChainSelect(onlyId);
4015
+ }, [chainOptions, chain, onChainSelect]);
4016
+ const mockWithdrawOrderState = useMemo(
4017
+ () => ({
4018
+ order_id: orderId ?? "",
4019
+ status: "pending",
4020
+ chain_id: "56",
4021
+ dst_token_amount: "0",
4022
+ target_chain_id: chain ?? "1",
4023
+ target_address: address ?? "0x",
4024
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
4025
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
4026
+ }),
4027
+ [orderId, chain, address]
4028
+ );
4029
+ useEffect(() => {
4030
+ if (orderId) {
4031
+ const t = setInterval(() => {
4032
+ getWithdrawOrder(orderId).then((order) => {
4033
+ setWithdrawOrder(order);
4034
+ if (order.status === "completed" && onShowToast) {
4035
+ onShowToast("Withdrawal completed");
4036
+ }
4037
+ }).catch(() => setWithdrawOrder(mockWithdrawOrderState));
4038
+ }, POLL_INTERVAL_MS);
4039
+ getWithdrawOrder(orderId).then(setWithdrawOrder).catch(() => setWithdrawOrder(mockWithdrawOrderState));
4040
+ return () => clearInterval(t);
4041
+ }
4042
+ if (!orderId && directActive) {
4043
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4044
+ const inferredAmountWei = (() => {
4045
+ if (withdrawDirectResult?.dst_token_amount) return withdrawDirectResult.dst_token_amount;
4046
+ const n = Number(amount || "0");
4047
+ return String(n > 0 ? BigInt(Math.floor(n * 1e18)) : 0n);
4048
+ })();
4049
+ const synthetic = {
4050
+ order_id: withdrawDirectResult?.order_id ?? `direct-${Date.now()}`,
4051
+ status: withdrawDirectResult?.status ?? "pending",
4052
+ chain_id: withdrawDirectResult?.chain_id ?? String(fundingChainId ?? "3131"),
4053
+ dst_token_amount: inferredAmountWei,
4054
+ fee: withdrawDirectResult?.fee ?? feeDisplay,
4055
+ target_chain_id: withdrawDirectResult?.target_chain_id ?? (chain ?? ""),
4056
+ target_address: withdrawDirectResult?.target_address ?? (address ?? ""),
4057
+ funding_tx_hash: withdrawDirectResult?.funding_tx_hash ?? txHash,
4058
+ dst_tx_hash: withdrawDirectResult?.dst_tx_hash,
4059
+ out_tx_hash: withdrawDirectResult?.out_tx_hash,
4060
+ created_at: withdrawDirectResult?.created_at ?? now,
4061
+ updated_at: withdrawDirectResult?.updated_at ?? now,
4062
+ one_time_address: withdrawDirectResult?.one_time_address
4063
+ };
4064
+ setWithdrawOrder(synthetic);
4065
+ return;
4066
+ }
4067
+ setWithdrawOrder(null);
4068
+ }, [orderId, directActive, withdrawDirectResult, amount, feeDisplay, chain, address, txHash, fundingChainId, onShowToast, mockWithdrawOrderState]);
4069
+ const completedKeyRef = useRef(null);
4070
+ useEffect(() => {
4071
+ if (withdrawOrder?.status !== "completed") return;
4072
+ const key = orderId ?? withdrawOrder.order_id;
4073
+ if (key && completedKeyRef.current !== key) {
4074
+ completedKeyRef.current = key;
4075
+ onWithdrawCompleted?.();
4076
+ }
4077
+ if (!trackingWithdraw) completedKeyRef.current = null;
4078
+ }, [withdrawOrder?.status, orderId, trackingWithdraw, onWithdrawCompleted]);
4079
+ const receiveAmount = useMemo(() => {
4080
+ if (receiveAmountProp) {
4081
+ const n = Number(receiveAmountProp);
4082
+ if (!Number.isNaN(n)) return n.toFixed(2);
4083
+ return receiveAmountProp;
4084
+ }
4085
+ if (!apiQuote?.token_amount || !apiQuote?.token_symbol) return void 0;
4086
+ const amount2 = Number(apiQuote.token_amount);
4087
+ const formatted = Number.isNaN(amount2) ? apiQuote.token_amount : amount2.toFixed(2);
4088
+ return `\u2248 ${formatted} (wei) ${apiQuote.token_symbol}`;
4089
+ }, [receiveAmountProp, apiQuote]);
4090
+ const quoteExpired = useMemo(() => {
4091
+ if (!apiQuote?.expires_at) return false;
4092
+ try {
4093
+ return new Date(apiQuote.expires_at).getTime() < Date.now();
4094
+ } catch {
4095
+ return false;
4096
+ }
4097
+ }, [apiQuote?.expires_at]);
4098
+ const handleRefreshQuote = useCallback(() => {
4099
+ if (!apiChains?.length || !token || !chain) return;
4100
+ const tokenAddress = getTokenAddressForChain2(apiChains, chain, token);
4101
+ if (!tokenAddress) return;
4102
+ const amountNum = amount && Number(amount) > 0 ? Number(amount) : 1;
4103
+ const amountWei = String(BigInt(Math.floor(amountNum * 1e18)));
4104
+ setLoadingQuote(true);
4105
+ quote({
4106
+ direction: "withdraw",
4107
+ chain_id: chain,
4108
+ token_address: tokenAddress,
4109
+ dst_token_amount: amountWei
4110
+ }).then((q) => setApiQuote(q ?? null)).catch(() => {
4111
+ setApiQuote({
4112
+ token_address: tokenAddress,
4113
+ token_symbol: token,
4114
+ token_decimals: 18,
4115
+ rate: "1",
4116
+ chain_id: Number(chain) || 56,
4117
+ token_amount: amountWei,
4118
+ expires_at: new Date(Date.now() + 6e4).toISOString()
4119
+ });
4120
+ }).finally(() => setLoadingQuote(false));
4121
+ }, [apiChains, token, chain, amount]);
4122
+ const handleAmountChange = useCallback(
4123
+ (e) => {
4124
+ const raw = e.target.value;
4125
+ const maxNum = balance ? parseBalanceNumber(balance) : null;
4126
+ if (maxNum != null && raw !== "" && raw !== ".") {
4127
+ const num = Number(raw);
4128
+ if (!Number.isNaN(num) && num > maxNum) {
4129
+ onAmountChange?.({
4130
+ ...e,
4131
+ target: { ...e.target, value: String(maxNum) }
4132
+ });
4133
+ return;
4134
+ }
4135
+ }
4136
+ onAmountChange?.(e);
4137
+ },
4138
+ [balance, onAmountChange]
4139
+ );
4140
+ if (!session) {
4141
+ return /* @__PURE__ */ jsx(LoginRequiredOverlay, { title: "Withdraw", onSignIn, onClose });
4142
+ }
4143
+ const activeStep = amount ? 3 : chain ? 2 : token ? 1 : address ? 0 : 0;
4144
+ const canSubmit = address && token && chain && amount;
4145
+ const isSubmitting = status !== "idle";
4146
+ const orderInProgress = trackingWithdraw && (!withdrawOrder || withdrawOrder.status !== "completed");
4147
+ const orderSucceeded = trackingWithdraw && withdrawOrder?.status === "completed";
4148
+ return /* @__PURE__ */ jsxs(
4149
+ ModalFrame,
4150
+ {
4151
+ onClose,
4152
+ contentStyle: {
4153
+ justifyContent: "space-between",
4154
+ padding: "24px"
4155
+ },
4156
+ children: [
4157
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 32 }, children: [
4158
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: /* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: 24, fontWeight: 600, lineHeight: 1.4 }, children: "Withdraw" }) }),
4159
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 16 }, children: [
4160
+ /* @__PURE__ */ jsx(
4161
+ "div",
4162
+ {
4163
+ style: {
4164
+ opacity: trackingWithdraw ? 0 : 1,
4165
+ maxWidth: trackingWithdraw ? 0 : 48,
4166
+ overflow: "hidden",
4167
+ transition: "opacity 0.3s ease, max-width 0.35s ease"
4168
+ },
4169
+ children: /* @__PURE__ */ jsx(
4170
+ StepIndicator,
4171
+ {
4172
+ steps: 4,
4173
+ stepActive: [!!address, !!token, !!chain, !!apiQuote],
4174
+ activeStep
4175
+ }
4176
+ )
4177
+ }
4178
+ ),
4179
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, position: "relative", minHeight: 400 }, children: [
4180
+ /* @__PURE__ */ jsxs(
4181
+ "div",
4182
+ {
4183
+ style: {
4184
+ position: "absolute",
4185
+ inset: 0,
4186
+ display: "flex",
4187
+ flexDirection: "column",
4188
+ alignItems: "center",
4189
+ justifyContent: "center",
4190
+ gap: 12,
4191
+ padding: "0 16px",
4192
+ opacity: trackingWithdraw ? 1 : 0,
4193
+ maxHeight: trackingWithdraw ? 400 : 0,
4194
+ overflow: "hidden",
4195
+ pointerEvents: trackingWithdraw ? "auto" : "none",
4196
+ transition: "opacity 0.3s ease, max-height 0.35s ease"
4197
+ },
4198
+ children: [
4199
+ orderInProgress && /* @__PURE__ */ jsxs(
4200
+ "div",
4201
+ {
4202
+ style: {
4203
+ display: "flex",
4204
+ flexDirection: "column",
4205
+ alignItems: "center",
4206
+ justifyContent: "center",
4207
+ gap: 32
4208
+ },
4209
+ children: [
4210
+ /* @__PURE__ */ jsx(
4211
+ "span",
4212
+ {
4213
+ style: {
4214
+ display: "inline-block",
4215
+ width: 60,
4216
+ height: 60,
4217
+ border: `3px solid ${colors.border}`,
4218
+ borderTopColor: colors.textPrimary,
4219
+ borderRadius: "50%",
4220
+ animation: "withdraw-modal-spin 0.8s linear infinite"
4221
+ },
4222
+ "aria-hidden": true
4223
+ }
4224
+ ),
4225
+ /* @__PURE__ */ jsx(
4226
+ "span",
4227
+ {
4228
+ style: {
4229
+ fontSize: 20,
4230
+ fontWeight: 600,
4231
+ color: colors.textPrimary,
4232
+ textAlign: "center",
4233
+ fontFamily: fonts.family,
4234
+ lineHeight: 1.4
4235
+ },
4236
+ children: "Processing withdrawal..."
4237
+ }
4238
+ )
4239
+ ]
4240
+ }
4241
+ ),
4242
+ orderSucceeded && (() => {
4243
+ const destTxHash = withdrawOrder.dst_tx_hash ?? withdrawOrder.out_tx_hash;
4244
+ const targetChainName = apiChains?.find((c) => c.chain_id === withdrawOrder.target_chain_id)?.network ?? withdrawOrder.target_chain_id ?? "\u2014";
4245
+ const explorerUrl = destTxHash && withdrawOrder.target_chain_id ? getExplorerUrl(withdrawOrder.target_chain_id, { txId: destTxHash }) : null;
4246
+ const copyHash = () => {
4247
+ if (destTxHash && typeof navigator?.clipboard?.writeText === "function") {
4248
+ navigator.clipboard.writeText(destTxHash);
4249
+ onShowToast?.("Copied");
4250
+ }
4251
+ };
4252
+ return /* @__PURE__ */ jsxs(
4253
+ "div",
4254
+ {
4255
+ style: {
4256
+ display: "flex",
4257
+ flexDirection: "column",
4258
+ alignItems: "center",
4259
+ gap: 20,
4260
+ width: "100%",
4261
+ maxWidth: 412
4262
+ },
4263
+ children: [
4264
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 24 }, children: [
4265
+ /* @__PURE__ */ jsx(
4266
+ "span",
4267
+ {
4268
+ style: {
4269
+ display: "flex",
4270
+ alignItems: "center",
4271
+ justifyContent: "center",
4272
+ width: 60,
4273
+ height: 60,
4274
+ borderRadius: "50%",
4275
+ color: "#22c55e",
4276
+ fontSize: 40,
4277
+ lineHeight: 1,
4278
+ fontWeight: 700
4279
+ },
4280
+ "aria-hidden": true,
4281
+ children: /* @__PURE__ */ jsx(SuccessIcon, {})
4282
+ }
4283
+ ),
4284
+ /* @__PURE__ */ jsx(
4285
+ "span",
4286
+ {
4287
+ style: {
4288
+ fontSize: 20,
4289
+ fontWeight: 600,
4290
+ color: colors.textPrimary,
4291
+ textAlign: "center",
4292
+ fontFamily: fonts.family,
4293
+ lineHeight: 1.4
4294
+ },
4295
+ children: "Withdrawal successful"
4296
+ }
4297
+ )
4298
+ ] }),
4299
+ /* @__PURE__ */ jsxs(
4300
+ "div",
4301
+ {
4302
+ style: {
4303
+ display: "flex",
4304
+ flexDirection: "column",
4305
+ gap: 4,
4306
+ width: "100%"
4307
+ },
4308
+ children: [
4309
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "8px 0", height: 36 }, children: [
4310
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textSecondary }, children: "Amount" }),
4311
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textPrimary }, children: [
4312
+ weiToEtherDisplay(withdrawOrder.dst_token_amount),
4313
+ " ",
4314
+ tokenSymbol
4315
+ ] })
4316
+ ] }),
4317
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "8px 0", height: 36 }, children: [
4318
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textSecondary }, children: "Fee" }),
4319
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textPrimary }, children: withdrawOrder.fee ?? feeDisplay ?? "\u2014" })
4320
+ ] }),
4321
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "8px 0", height: 36 }, children: [
4322
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textSecondary }, children: "Network" }),
4323
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textPrimary }, children: targetChainName })
4324
+ ] }),
4325
+ destTxHash && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "8px 0", minHeight: 38 }, children: [
4326
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textSecondary }, children: "Transaction Hash" }),
4327
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
4328
+ explorerUrl ? /* @__PURE__ */ jsxs(
4329
+ "a",
4330
+ {
4331
+ href: explorerUrl,
4332
+ target: "_blank",
4333
+ rel: "noopener noreferrer",
4334
+ style: { fontSize: 14, color: colors.textPrimary, textDecoration: "underline" },
4335
+ children: [
4336
+ destTxHash.slice(0, 10),
4337
+ "...",
4338
+ destTxHash.slice(-8)
4339
+ ]
4340
+ }
4341
+ ) : /* @__PURE__ */ jsxs("span", { style: { fontSize: 14, color: colors.textPrimary }, children: [
4342
+ destTxHash.slice(0, 10),
4343
+ "...",
4344
+ destTxHash.slice(-8)
4345
+ ] }),
4346
+ /* @__PURE__ */ jsx(
4347
+ "button",
4348
+ {
4349
+ type: "button",
4350
+ onClick: copyHash,
4351
+ "aria-label": "Copy hash",
4352
+ style: {
4353
+ padding: 0,
4354
+ border: "none",
4355
+ background: "transparent",
4356
+ color: colors.textPrimary,
4357
+ cursor: "pointer",
4358
+ display: "flex",
4359
+ alignItems: "center",
4360
+ justifyContent: "center",
4361
+ width: 16,
4362
+ height: 16
4363
+ },
4364
+ children: /* @__PURE__ */ jsx(CopyIcon2, {})
4365
+ }
4366
+ )
4367
+ ] })
4368
+ ] })
4369
+ ]
4370
+ }
4371
+ ),
4372
+ /* @__PURE__ */ jsx("div", { style: { paddingTop: 24, width: "100%", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsx(
4373
+ "button",
4374
+ {
4375
+ type: "button",
4376
+ onClick: () => {
4377
+ setDirectActive(false);
4378
+ setWithdrawOrder(null);
4379
+ (onStartAnotherWithdrawal ?? onClose)?.();
4380
+ },
4381
+ style: {
4382
+ width: 274,
4383
+ padding: "12px 0",
4384
+ borderRadius: radii.full,
4385
+ border: `1px solid ${colors.buttonDisabledBorder}`,
4386
+ background: colors.textPrimary,
4387
+ color: "#121214",
4388
+ fontSize: 16,
4389
+ fontWeight: 500,
4390
+ lineHeight: 1.4,
4391
+ fontFamily: fonts.family,
4392
+ cursor: "pointer",
4393
+ textAlign: "center"
4394
+ },
4395
+ children: "Start another withdrawal"
4396
+ }
4397
+ ) })
4398
+ ]
4399
+ }
4400
+ );
4401
+ })()
4402
+ ]
4403
+ }
4404
+ ),
4405
+ /* @__PURE__ */ jsx(
4406
+ "div",
4407
+ {
4408
+ style: {
4409
+ opacity: trackingWithdraw ? 0 : 1,
4410
+ maxHeight: trackingWithdraw ? 0 : 1200,
4411
+ overflow: "hidden",
4412
+ pointerEvents: trackingWithdraw ? "none" : "auto",
4413
+ transition: "opacity 0.3s ease, max-height 0.35s ease"
4414
+ },
4415
+ children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 40 }, children: [
4416
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8, width: "100%" }, children: [
4417
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textPrimary }, children: "Recipient address" }),
4418
+ /* @__PURE__ */ jsx(
4419
+ "div",
4420
+ {
4421
+ style: {
4422
+ display: "flex",
4423
+ alignItems: "center",
4424
+ height: 44,
4425
+ padding: "0 16px",
4426
+ borderRadius: radii.input,
4427
+ border: `1px solid ${addressInputFocused ? colors.borderFocused : colors.border}`,
4428
+ boxSizing: "border-box"
4429
+ },
4430
+ children: /* @__PURE__ */ jsx(
4431
+ "input",
4432
+ {
4433
+ ref: addressInputRef,
4434
+ value: address,
4435
+ onChange: onAddressChange,
4436
+ onFocus: () => setAddressInputFocused(true),
4437
+ onBlur: () => setAddressInputFocused(false),
4438
+ spellCheck: false,
4439
+ placeholder: "0x",
4440
+ style: {
4441
+ flex: 1,
4442
+ border: "none",
4443
+ outline: "none",
4444
+ background: "transparent",
4445
+ color: colors.textPrimary,
4446
+ fontSize: 14,
4447
+ fontFamily: fonts.family,
4448
+ lineHeight: 1.4,
4449
+ padding: 0
4450
+ }
4451
+ }
4452
+ )
4453
+ }
4454
+ )
4455
+ ] }),
4456
+ /* @__PURE__ */ jsx(
4457
+ DropdownField,
4458
+ {
4459
+ label: "Select token",
4460
+ placeholder: loadingChains ? "Loading\u2026" : "Token",
4461
+ value: token,
4462
+ options: tokenOptions,
4463
+ onSelect: onTokenSelect
4464
+ }
4465
+ ),
4466
+ /* @__PURE__ */ jsx(
4467
+ DropdownField,
4468
+ {
4469
+ label: "Select chain",
4470
+ placeholder: loadingChains ? "Loading\u2026" : "Chain",
4471
+ value: chain,
4472
+ options: chainOptions,
4473
+ onSelect: onChainSelect
4474
+ }
4475
+ ),
4476
+ apiQuote && token && chain && /* @__PURE__ */ jsx(
4477
+ "div",
4478
+ {
4479
+ style: {
4480
+ padding: "12px 16px",
4481
+ borderRadius: radii.card,
4482
+ border: `1px solid ${colors.border}`,
4483
+ display: "flex",
4484
+ flexDirection: "column",
4485
+ gap: 8
4486
+ },
4487
+ children: loadingQuote ? /* @__PURE__ */ jsx("span", { style: { fontSize: 13, color: colors.textSecondary }, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4488
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: 13, color: colors.textSecondary }, children: [
4489
+ "Rate: 1 ",
4490
+ FUNDING_TOKEN_SYMBOL2,
4491
+ " = ",
4492
+ apiQuote.rate,
4493
+ " ",
4494
+ apiQuote.token_symbol
4495
+ ] }),
4496
+ apiQuote.expires_at && /* @__PURE__ */ jsx(
4497
+ Countdown,
4498
+ {
4499
+ expiresAt: apiQuote.expires_at,
4500
+ isExpired: quoteExpired,
4501
+ onExpired: handleRefreshQuote
4502
+ }
4503
+ ),
4504
+ quoteExpired && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
4505
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 13, color: "#f59e0b" }, children: "Quote expired, please refresh" }),
4506
+ /* @__PURE__ */ jsx(
4507
+ "button",
4508
+ {
4509
+ type: "button",
4510
+ onClick: handleRefreshQuote,
4511
+ style: {
4512
+ padding: "4px 12px",
4513
+ fontSize: 12,
4514
+ borderRadius: radii.pill,
4515
+ border: `1px solid ${colors.border}`,
4516
+ background: "transparent",
4517
+ color: colors.textPrimary,
4518
+ cursor: "pointer",
4519
+ fontFamily: fonts.family
4520
+ },
4521
+ children: "Refresh"
4522
+ }
4523
+ )
4524
+ ] })
4525
+ ] })
4526
+ }
4527
+ ),
4528
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
4529
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
4530
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textPrimary }, children: "Amount" }),
4531
+ balance && /* @__PURE__ */ jsxs("span", { style: { fontSize: 13, lineHeight: 1.2, color: colors.textSecondary }, children: [
4532
+ "Balance: \xA0",
4533
+ formatBalanceTo2Decimals(balance),
4534
+ " ",
4535
+ FUNDING_TOKEN_SYMBOL2
4536
+ ] })
4537
+ ] }),
4538
+ /* @__PURE__ */ jsxs(
4539
+ "div",
4540
+ {
4541
+ style: {
4542
+ display: "flex",
4543
+ alignItems: "center",
4544
+ justifyContent: "space-between",
4545
+ height: 48,
4546
+ padding: "0 16px",
4547
+ borderRadius: radii.input,
4548
+ border: `1px solid ${amountInputFocused ? colors.borderFocused : colors.border}`,
4549
+ boxSizing: "border-box"
4550
+ },
4551
+ children: [
4552
+ /* @__PURE__ */ jsx(
4553
+ "input",
4554
+ {
4555
+ value: amount,
4556
+ onChange: handleAmountChange,
4557
+ onFocus: () => setAmountInputFocused(true),
4558
+ onBlur: () => setAmountInputFocused(false),
4559
+ placeholder: "0.00",
4560
+ type: "text",
4561
+ inputMode: "decimal",
4562
+ style: {
4563
+ flex: 1,
4564
+ border: "none",
4565
+ outline: "none",
4566
+ background: "transparent",
4567
+ color: amount ? colors.textPrimary : colors.textSecondary,
4568
+ fontSize: 14,
4569
+ fontFamily: fonts.family,
4570
+ lineHeight: 1.4,
4571
+ padding: 0
4572
+ }
4573
+ }
4574
+ ),
4575
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: /* @__PURE__ */ jsx(
4576
+ "button",
4577
+ {
4578
+ type: "button",
4579
+ onClick: onMaxClick,
4580
+ style: {
4581
+ background: colors.textPrimary,
4582
+ border: "none",
4583
+ borderRadius: radii.pill,
4584
+ padding: "2px 8px",
4585
+ fontSize: 12,
4586
+ lineHeight: 1.4,
4587
+ fontWeight: 400,
4588
+ color: "#15181D",
4589
+ fontFamily: fonts.family,
4590
+ cursor: "pointer"
4591
+ },
4592
+ children: "Max"
4593
+ }
4594
+ ) })
4595
+ ]
4596
+ }
4597
+ )
4598
+ ] }) })
4599
+ ] })
4600
+ }
4601
+ )
4602
+ ] })
4603
+ ] })
4604
+ ] }),
4605
+ /* @__PURE__ */ jsxs("div", { style: { padding: "20px 20px 0", display: "flex", flexDirection: "column", gap: 10, alignItems: "center" }, id: "WithdrawModalReceiveAmount", children: [
4606
+ !trackingWithdraw && amount && Number(amount) > 0 && /* @__PURE__ */ jsxs("span", { style: { fontSize: 14, lineHeight: 1.4, color: colors.textPrimary }, children: [
4607
+ "You will receive : ",
4608
+ receiveAmount
4609
+ ] }),
4610
+ orderInProgress && withdrawOrder && (() => {
4611
+ const fundingHash = txHash ?? withdrawOrder?.funding_tx_hash;
4612
+ const showFundingLink = fundingHash && fundingChainId;
4613
+ try {
4614
+ return /* @__PURE__ */ jsx("div", { style: { display: "none", flexDirection: "column", gap: 6, alignItems: "center" }, children: showFundingLink && /* @__PURE__ */ jsx(
4615
+ "a",
4616
+ {
4617
+ href: getExplorerUrl(fundingChainId, { txId: fundingHash }),
4618
+ target: "_blank",
4619
+ rel: "noopener noreferrer",
4620
+ style: { fontSize: 13, color: colors.textPrimary, textDecoration: "underline" },
4621
+ children: "Withdraw request transaction on explorer"
4622
+ }
4623
+ ) });
4624
+ } catch {
4625
+ return /* @__PURE__ */ jsx("span", { style: { fontSize: 13, color: colors.textPrimary }, children: "Withdraw in progress." });
4626
+ }
4627
+ })(),
4628
+ orderInProgress && withdrawOrder && /* @__PURE__ */ jsxs("span", { style: { fontSize: 13, color: colors.textSecondary, display: "none", alignItems: "center", gap: 6 }, children: [
4629
+ "Order status: ",
4630
+ withdrawOrder.status,
4631
+ /* @__PURE__ */ jsx(
4632
+ "span",
4633
+ {
4634
+ style: {
4635
+ display: "inline-block",
4636
+ width: 10,
4637
+ height: 10,
4638
+ border: `2px solid ${colors.textSecondary}`,
4639
+ borderTopColor: "transparent",
4640
+ borderRadius: "50%",
4641
+ animation: "withdraw-modal-spin 0.7s linear infinite"
4642
+ },
4643
+ "aria-hidden": true
4644
+ }
4645
+ )
4646
+ ] }),
4647
+ /* @__PURE__ */ jsx("style", { children: `@keyframes withdraw-modal-spin { to { transform: rotate(360deg); } }` }),
4648
+ orderSucceeded || trackingWithdraw ? null : /* @__PURE__ */ jsx(
4649
+ SubmitButton,
4650
+ {
4651
+ disabled: !canSubmit || isSubmitting,
4652
+ status,
4653
+ onClick: () => onSubmit?.({
4654
+ toAddress: address,
4655
+ amount: amount ?? "",
4656
+ token: token ?? "",
4657
+ tokenAddress: resolvedTokenAddress ?? apiQuote?.token_address ?? "",
4658
+ chain: chain ?? ""
4659
+ })
4660
+ }
4661
+ )
4662
+ ] })
4663
+ ]
4664
+ }
4665
+ );
4666
+ };
4667
+ var SubmitButton = ({ disabled, status, onClick }) => {
4668
+ const labels = {
4669
+ idle: disabled ? "Please fill in withdrawal information" : "Submit",
4670
+ pending: "Processing...",
4671
+ success: "Withdrawal successful",
4672
+ manual_review: "Under manual review"
4673
+ };
4674
+ const isDisabled = disabled || status !== "idle";
4675
+ return /* @__PURE__ */ jsx(
4676
+ "button",
4677
+ {
4678
+ type: "button",
4679
+ disabled: isDisabled,
4680
+ onClick,
4681
+ style: {
4682
+ width: 364,
4683
+ padding: "12px 0",
4684
+ borderRadius: radii.full,
4685
+ border: isDisabled ? `1px solid ${colors.buttonDisabledBorder}` : "none",
4686
+ background: isDisabled ? colors.buttonDisabledBg : colors.textPrimary,
4687
+ color: isDisabled ? colors.textSecondary : "#15181D",
4688
+ fontSize: 16,
4689
+ fontWeight: 500,
4690
+ lineHeight: 1.4,
4691
+ fontFamily: fonts.family,
4692
+ cursor: isDisabled ? "not-allowed" : "pointer",
4693
+ textAlign: "center"
4694
+ },
4695
+ children: labels[status]
4696
+ }
4697
+ );
4698
+ };
4699
+
4700
+ export { ClientIds, DEFAULT_FUNDING_CHAIN_ID, DEFAULT_FUNDING_TOKEN_ADDRESS, DepositDetailsPanel, DepositModal, DropdownField, SignInModal, WalletSelectionModal, WithdrawModal, clearSocialAccountInstance2 as clearSocialAccountInstance, configureMerchantApi, createDepositController, createFundingWithdrawExecutor, createMarketDataProvider, createOrder, createPredicateMarketPolicyAdapter, createWithdrawController, fetchErc20Balance, fetchFundingTokenBalance, findTokenDataFromChains, getChainInfo, getChains, getDepositOrder, getEnv, getExplorerUrl, getFixedAuthConfig, getFundingTokenAddress, getMerchantApiClient, getSDKConfig, getWithdrawOrder, initSDK, isFedCMSupported, isUsdtWithdrawDirect, notifyTwitterCallback, parseUnits, quote, registerPlatform, signInWithGoogle, signInWithTwitter, tryAutoReconnect };