@dynamic-labs/sdk-react-core 4.84.1 → 4.85.0

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 (34) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/package.cjs +3 -3
  3. package/package.js +3 -3
  4. package/package.json +14 -14
  5. package/src/index.d.ts +1 -1
  6. package/src/lib/components/SendBalancePageLayout/components/TokensBalanceDropdown/TokensBalanceDropdown.cjs +5 -1
  7. package/src/lib/components/SendBalancePageLayout/components/TokensBalanceDropdown/TokensBalanceDropdown.js +5 -1
  8. package/src/lib/context/OnrampContext/utils/getOnrampProviders.cjs +2 -6
  9. package/src/lib/context/OnrampContext/utils/getOnrampProviders.js +4 -8
  10. package/src/lib/data/api/onramp/onramp.cjs +26 -1
  11. package/src/lib/data/api/onramp/onramp.d.ts +11 -1
  12. package/src/lib/data/api/onramp/onramp.js +26 -1
  13. package/src/lib/utils/functions/onrampProviders/index.cjs +1 -0
  14. package/src/lib/utils/functions/onrampProviders/index.js +1 -0
  15. package/src/lib/utils/hooks/index.d.ts +1 -1
  16. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs +81 -10
  17. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.d.ts +18 -2
  18. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +82 -11
  19. package/src/lib/utils/hooks/useDynamicWaas/useDynamicWaas.cjs +4 -4
  20. package/src/lib/utils/hooks/useDynamicWaas/useDynamicWaas.js +4 -4
  21. package/src/lib/utils/hooks/usePrivateTokenBalances/index.d.ts +1 -1
  22. package/src/lib/utils/hooks/usePrivateTokenBalances/usePrivateTokenBalances.cjs +10 -2
  23. package/src/lib/utils/hooks/usePrivateTokenBalances/usePrivateTokenBalances.d.ts +17 -2
  24. package/src/lib/utils/hooks/usePrivateTokenBalances/usePrivateTokenBalances.js +10 -2
  25. package/src/lib/utils/hooks/useSyncDynamicWaas/instrumentWalletCreation.cjs +60 -0
  26. package/src/lib/utils/hooks/useSyncDynamicWaas/instrumentWalletCreation.d.ts +29 -0
  27. package/src/lib/utils/hooks/useSyncDynamicWaas/instrumentWalletCreation.js +55 -0
  28. package/src/lib/utils/hooks/useSyncDynamicWaas/useSyncDynamicWaas.cjs +14 -24
  29. package/src/lib/utils/hooks/useSyncDynamicWaas/useSyncDynamicWaas.js +14 -24
  30. package/src/lib/views/TransactionConfirmationView/TransactionConfirmationView.cjs +17 -1
  31. package/src/lib/views/TransactionConfirmationView/TransactionConfirmationView.js +17 -1
  32. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/optimisticShield.cjs +28 -12
  33. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/optimisticShield.d.ts +8 -3
  34. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/optimisticShield.js +28 -12
@@ -1,9 +1,10 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../_virtual/_tslib.js';
3
- import { useState, useRef, useCallback, useEffect } from 'react';
3
+ import { useState, useMemo, useRef, useCallback, useEffect } from 'react';
4
4
  import { ChainEnum } from '@dynamic-labs/sdk-api-core';
5
5
  import '../../../context/DynamicContext/useDynamicContext/useDynamicContext.js';
6
6
  import { useInternalDynamicContext } from '../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
7
+ import { useInternalUserWallets } from '../../../context/UserWalletsContext/UserWalletsContext.js';
7
8
  import { getAleoCuratedPrices } from '../../../data/api/aleo/getAleoCuratedPrices.js';
8
9
  import { getEnvironmentId } from '../../../store/state/dynamicContextProps/dynamicContextProps.js';
9
10
 
@@ -279,14 +280,37 @@ const buildTokenBalances = (records, networkId, lookupCurated) => {
279
280
  * - The connector doesn't expose `listOwnedRecords` (e.g. external Aleo wallet)
280
281
  * - The user owns no records that match a known program/record pair
281
282
  */
282
- const useAleoShieldedBalances = () => {
283
+ const useAleoShieldedBalances = (args = {}) => {
284
+ const { accountAddress, tokenAddresses, includeNativeBalance = true, includeFiat = true, chainName, networkId, } = args;
283
285
  const { primaryWallet, network } = useInternalDynamicContext();
286
+ const { userWallets } = useInternalUserWallets();
284
287
  const [tokenBalances, setTokenBalances] = useState([]);
285
288
  const [isLoading, setIsLoading] = useState(false);
286
289
  const [error, setError] = useState();
287
- const connector = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector;
290
+ // `accountAddress` is treated as an override of the primary wallet:
291
+ // walk the user-wallets list looking for a matching address (case-
292
+ // insensitive to be tolerant of how the address is formatted at the
293
+ // call site — Aleo addresses are bech32 and casing-insensitive in
294
+ // practice). When no `accountAddress` is provided, fall back to the
295
+ // primary wallet to preserve the existing single-wallet semantics.
296
+ const targetWallet = useMemo(() => {
297
+ var _a;
298
+ if (!accountAddress)
299
+ return primaryWallet;
300
+ const normalized = accountAddress.toLowerCase();
301
+ return ((_a = userWallets.find((w) => { var _a; return ((_a = w.address) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === normalized; })) !== null && _a !== void 0 ? _a : undefined);
302
+ }, [accountAddress, primaryWallet, userWallets]);
303
+ const connector = targetWallet === null || targetWallet === void 0 ? void 0 : targetWallet.connector;
288
304
  const isAleo = (connector === null || connector === void 0 ? void 0 : connector.connectedChain) === ChainEnum.Aleo;
289
- const supportsShielded = isAleo &&
305
+ // When a `chainName` override is passed, treat anything other than
306
+ // `ChainEnum.Aleo` as "the caller explicitly asked for a non-Aleo
307
+ // chain we don't support yet" and short-circuit. Today Aleo is the
308
+ // only chain with a private-balance path, but customers should be
309
+ // able to call the public hook with whatever `chainName` matches
310
+ // their app's active chain and have it transparently no-op.
311
+ const chainNameSupported = chainName === undefined || chainName === ChainEnum.Aleo;
312
+ const supportsShielded = chainNameSupported &&
313
+ isAleo &&
290
314
  typeof (connector === null || connector === void 0 ? void 0 : connector.listOwnedRecords) === 'function';
291
315
  // Mirror the live connector into a ref so `fetchShielded` can read it
292
316
  // without depending on the (often unstable) object reference. Some test
@@ -296,7 +320,36 @@ const useAleoShieldedBalances = () => {
296
320
  const connectorRef = useRef(connector);
297
321
  connectorRef.current = connector;
298
322
  const connectorKey = connector === null || connector === void 0 ? void 0 : connector.key;
299
- const networkKey = network !== undefined && network !== null ? String(network) : undefined;
323
+ // When a `networkId` override is provided, use it instead of the
324
+ // context's `network` value when resolving the Aleo network param.
325
+ // Empty string falls back to undefined so `resolveAleoNetwork`
326
+ // returns `aleoNetworkParam: undefined` and the prices fetch is
327
+ // skipped (matching the behaviour when no network is known).
328
+ const effectiveNetwork = networkId !== null && networkId !== void 0 ? networkId : network;
329
+ const networkKey = effectiveNetwork !== undefined && effectiveNetwork !== null
330
+ ? String(effectiveNetwork)
331
+ : undefined;
332
+ // Normalise the address filter once per render into a stable
333
+ // primitive key (sorted, comma-joined, lowercased) so the
334
+ // `useCallback` dep below doesn't invalidate on every render when the
335
+ // caller passes a fresh array literal each time (which is the typical
336
+ // pattern in React function components). The matching Set is derived
337
+ // from the same key to keep both memos in lockstep.
338
+ const tokenAddressFilterKey = useMemo(() => {
339
+ if (!tokenAddresses)
340
+ return undefined;
341
+ return [...tokenAddresses]
342
+ .map((a) => a.toLowerCase())
343
+ .sort((a, b) => a.localeCompare(b))
344
+ .join('|');
345
+ }, [tokenAddresses]);
346
+ const tokenAddressFilter = useMemo(() => {
347
+ if (tokenAddressFilterKey === undefined)
348
+ return undefined;
349
+ if (tokenAddressFilterKey === '')
350
+ return new Set();
351
+ return new Set(tokenAddressFilterKey.split('|'));
352
+ }, [tokenAddressFilterKey]);
300
353
  const fetchShielded = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
301
354
  var _a;
302
355
  const liveConnector = connectorRef.current;
@@ -315,9 +368,15 @@ const useAleoShieldedBalances = () => {
315
368
  // token row, leaving the widget with no price source. Prices are
316
369
  // best-effort: a failure leaves balances unpriced rather than
317
370
  // dropping the shielded list entirely.
371
+ //
372
+ // When the caller opts out of fiat (`includeFiat: false`) we skip
373
+ // the curated-prices fetch entirely — same semantic as
374
+ // `useTokenBalances` honouring its own `includeFiat` flag. Logos
375
+ // for matched tokens then fall through to the bundled defaults
376
+ // (`ALEO_CREDITS_LOGO`, `UNKNOWN_TOKEN_LOGO`, spec overrides).
318
377
  const { safeNetworkId, aleoNetworkParam } = resolveAleoNetwork(networkKey);
319
378
  const environmentId = getEnvironmentId();
320
- const shouldFetchPrices = Boolean(aleoNetworkParam && environmentId);
379
+ const shouldFetchPrices = Boolean(includeFiat && aleoNetworkParam && environmentId);
321
380
  const [result, priceList] = yield Promise.all([
322
381
  liveConnector.listOwnedRecords(),
323
382
  shouldFetchPrices && aleoNetworkParam
@@ -330,11 +389,16 @@ const useAleoShieldedBalances = () => {
330
389
  const records = (_a = result === null || result === void 0 ? void 0 : result.records) !== null && _a !== void 0 ? _a : [];
331
390
  const lookupCurated = buildCuratedTokenLookup(priceList);
332
391
  const balances = [];
333
- const credits = buildCreditsBalance(records, safeNetworkId, lookupCurated);
334
- if (credits)
335
- balances.push(credits);
392
+ if (includeNativeBalance) {
393
+ const credits = buildCreditsBalance(records, safeNetworkId, lookupCurated);
394
+ if (credits)
395
+ balances.push(credits);
396
+ }
336
397
  balances.push(...buildTokenBalances(records, safeNetworkId, lookupCurated));
337
- setTokenBalances(balances);
398
+ const filtered = tokenAddressFilter
399
+ ? balances.filter((b) => { var _a; return tokenAddressFilter.has(((_a = b.address) !== null && _a !== void 0 ? _a : '').toLowerCase()); })
400
+ : balances;
401
+ setTokenBalances(filtered);
338
402
  }
339
403
  catch (err) {
340
404
  const msg = err instanceof Error ? err.message : String(err);
@@ -344,7 +408,14 @@ const useAleoShieldedBalances = () => {
344
408
  finally {
345
409
  setIsLoading(false);
346
410
  }
347
- }), [connectorKey, networkKey, supportsShielded]);
411
+ }), [
412
+ connectorKey,
413
+ includeFiat,
414
+ includeNativeBalance,
415
+ networkKey,
416
+ supportsShielded,
417
+ tokenAddressFilter,
418
+ ]);
348
419
  useEffect(() => {
349
420
  if (!supportsShielded) {
350
421
  setTokenBalances((prev) => (prev.length === 0 ? prev : []));
@@ -88,7 +88,7 @@ const configWaasWalletConnector = ({ walletConnector, environmentId, apiBaseUrl,
88
88
  };
89
89
  const useDynamicWaas = () => {
90
90
  var _a, _b, _c, _d, _e, _f, _g;
91
- const { setShowAuthFlow, primaryWallet } = useInternalDynamicContext.useInternalDynamicContext();
91
+ const { setShowAuthFlow } = useInternalDynamicContext.useInternalDynamicContext();
92
92
  const { addedWalletsIds, userWallets } = UserWalletsContext.useInternalUserWallets();
93
93
  const user = useUser.useUser();
94
94
  const apiBaseUrl = dynamicContextProps.useApiBaseUrl();
@@ -468,8 +468,8 @@ const useDynamicWaas = () => {
468
468
  });
469
469
  const upgradeToDynamicWaas = React.useCallback((_j) => _tslib.__awaiter(void 0, [_j], void 0, function* ({ privateKey, wallet, password, }) {
470
470
  isUpgrading.current = true;
471
- if (!primaryWallet) {
472
- throw new utils.DynamicError('Primary wallet not found');
471
+ if (!wallet) {
472
+ throw new utils.DynamicError('Wallet to upgrade was not provided');
473
473
  }
474
474
  const chainName = wallet.chain;
475
475
  const walletId = wallet.id;
@@ -514,7 +514,7 @@ const useDynamicWaas = () => {
514
514
  }
515
515
  throw new utils.DynamicError('Upgrade failed, please try again.');
516
516
  }
517
- }), [environmentId, getWaasWalletConnector, primaryWallet, refresh]);
517
+ }), [environmentId, getWaasWalletConnector, refresh]);
518
518
  /**
519
519
  * Returns WaaS wallet instances from `userWallets` filtered by `key === 'dynamicwaas'`.
520
520
  *
@@ -84,7 +84,7 @@ const configWaasWalletConnector = ({ walletConnector, environmentId, apiBaseUrl,
84
84
  };
85
85
  const useDynamicWaas = () => {
86
86
  var _a, _b, _c, _d, _e, _f, _g;
87
- const { setShowAuthFlow, primaryWallet } = useInternalDynamicContext();
87
+ const { setShowAuthFlow } = useInternalDynamicContext();
88
88
  const { addedWalletsIds, userWallets } = useInternalUserWallets();
89
89
  const user = useUser();
90
90
  const apiBaseUrl = useApiBaseUrl();
@@ -464,8 +464,8 @@ const useDynamicWaas = () => {
464
464
  });
465
465
  const upgradeToDynamicWaas = useCallback((_j) => __awaiter(void 0, [_j], void 0, function* ({ privateKey, wallet, password, }) {
466
466
  isUpgrading.current = true;
467
- if (!primaryWallet) {
468
- throw new DynamicError('Primary wallet not found');
467
+ if (!wallet) {
468
+ throw new DynamicError('Wallet to upgrade was not provided');
469
469
  }
470
470
  const chainName = wallet.chain;
471
471
  const walletId = wallet.id;
@@ -510,7 +510,7 @@ const useDynamicWaas = () => {
510
510
  }
511
511
  throw new DynamicError('Upgrade failed, please try again.');
512
512
  }
513
- }), [environmentId, getWaasWalletConnector, primaryWallet, refresh]);
513
+ }), [environmentId, getWaasWalletConnector, refresh]);
514
514
  /**
515
515
  * Returns WaaS wallet instances from `userWallets` filtered by `key === 'dynamicwaas'`.
516
516
  *
@@ -1,2 +1,2 @@
1
1
  export { usePrivateTokenBalances } from './usePrivateTokenBalances';
2
- export type { UsePrivateTokenBalancesReturn } from './usePrivateTokenBalances';
2
+ export type { UsePrivateTokenBalancesArgs, UsePrivateTokenBalancesReturn, } from './usePrivateTokenBalances';
@@ -5,8 +5,16 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
6
  var useAleoShieldedBalances = require('../useAleoShieldedBalances/useAleoShieldedBalances.cjs');
7
7
 
8
- const usePrivateTokenBalances = () => {
9
- const { tokenBalances, isLoading, error, refetch, supportsShielded } = useAleoShieldedBalances.useAleoShieldedBalances();
8
+ const usePrivateTokenBalances = (args = {}) => {
9
+ const { accountAddress, tokenAddresses, includeNativeBalance = false, includeFiat = false, chainName, networkId, } = args;
10
+ const { tokenBalances, isLoading, error, refetch, supportsShielded } = useAleoShieldedBalances.useAleoShieldedBalances({
11
+ accountAddress,
12
+ chainName,
13
+ includeFiat,
14
+ includeNativeBalance,
15
+ networkId,
16
+ tokenAddresses,
17
+ });
10
18
  return {
11
19
  error,
12
20
  isLoading,
@@ -1,4 +1,19 @@
1
- import { TokenBalance } from '@dynamic-labs/sdk-api-core';
1
+ import { ChainEnum, TokenBalance } from '@dynamic-labs/sdk-api-core';
2
+ /**
3
+ * Optional inputs that intentionally mirror the corresponding
4
+ * `useTokenBalances` params so callers can move between the public
5
+ * and private hooks with minimal call-site changes. Boolean defaults
6
+ * match `useTokenBalances` (`includeNativeBalance: false`,
7
+ * `includeFiat: false`) — opt in explicitly when you want either.
8
+ */
9
+ export type UsePrivateTokenBalancesArgs = {
10
+ accountAddress?: string;
11
+ tokenAddresses?: string[];
12
+ includeNativeBalance?: boolean;
13
+ includeFiat?: boolean;
14
+ chainName?: ChainEnum;
15
+ networkId?: number;
16
+ };
2
17
  export type UsePrivateTokenBalancesReturn = {
3
18
  tokenBalances: TokenBalance[];
4
19
  isLoading: boolean;
@@ -6,4 +21,4 @@ export type UsePrivateTokenBalancesReturn = {
6
21
  refetch: () => Promise<void>;
7
22
  supportsPrivateBalances: boolean;
8
23
  };
9
- export declare const usePrivateTokenBalances: () => UsePrivateTokenBalancesReturn;
24
+ export declare const usePrivateTokenBalances: (args?: UsePrivateTokenBalancesArgs) => UsePrivateTokenBalancesReturn;
@@ -1,8 +1,16 @@
1
1
  'use client'
2
2
  import { useAleoShieldedBalances } from '../useAleoShieldedBalances/useAleoShieldedBalances.js';
3
3
 
4
- const usePrivateTokenBalances = () => {
5
- const { tokenBalances, isLoading, error, refetch, supportsShielded } = useAleoShieldedBalances();
4
+ const usePrivateTokenBalances = (args = {}) => {
5
+ const { accountAddress, tokenAddresses, includeNativeBalance = false, includeFiat = false, chainName, networkId, } = args;
6
+ const { tokenBalances, isLoading, error, refetch, supportsShielded } = useAleoShieldedBalances({
7
+ accountAddress,
8
+ chainName,
9
+ includeFiat,
10
+ includeNativeBalance,
11
+ networkId,
12
+ tokenAddresses,
13
+ });
6
14
  return {
7
15
  error,
8
16
  isLoading,
@@ -0,0 +1,60 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var _tslib = require('../../../../../_virtual/_tslib.cjs');
7
+ require('@dynamic-labs/iconic');
8
+ require('@dynamic-labs/wallet-connector-core');
9
+ require('react');
10
+ require('react/jsx-runtime');
11
+ require('../../../context/ViewContext/ViewContext.cjs');
12
+ var logger = require('../../../shared/logger.cjs');
13
+ require('@dynamic-labs/wallet-book');
14
+ require('@dynamic-labs/utils');
15
+ require('../../constants/colors.cjs');
16
+ require('../../constants/values.cjs');
17
+ require('@dynamic-labs/sdk-api-core');
18
+ require('../../../shared/consts/index.cjs');
19
+
20
+ /**
21
+ * Soft watchdog for the embedded-wallet auto-creation ceremony. Long enough to
22
+ * clear a healthy MPC ceremony (observed ~7s, iframe load timeout is 10s) so a
23
+ * fire here means the flow genuinely stalled rather than just being slow.
24
+ */
25
+ const AUTO_WALLET_CREATION_TIMEOUT_MS = 30000;
26
+ /**
27
+ * Wraps the auto-wallet-creation ceremony so that "silent" failures carry a
28
+ * reason. Without this, a ceremony that hangs (promise never settles) or a user
29
+ * who navigates away mid-flow produces an `initiated` log with no `success` or
30
+ * `failed` counterpart, leaving the failure undiagnosable.
31
+ *
32
+ * Emits:
33
+ * - `auto_wallet_creation_timeout` if `run` has not settled within `timeoutMs`.
34
+ * - `auto_wallet_creation_abandoned` if the page is hidden while `run` is still
35
+ * in flight (relies on the logger's keepalive transport to survive unload).
36
+ *
37
+ * The watchdog is observational: it never aborts `run`, and its return value /
38
+ * rejection is passed through unchanged.
39
+ */
40
+ const instrumentWalletCreation = (_a) => _tslib.__awaiter(void 0, [_a], void 0, function* ({ run, logData, timeoutMs = AUTO_WALLET_CREATION_TIMEOUT_MS, }) {
41
+ var _b, _c;
42
+ const startTime = Date.now();
43
+ const timeoutId = setTimeout(() => {
44
+ logger.logger.instrument('Auto wallet creation timed out', Object.assign(Object.assign({}, logData), { key: 'auto_wallet_creation_timeout', reason: 'timeout', time: Date.now() - startTime }));
45
+ }, timeoutMs);
46
+ const handlePageHide = () => {
47
+ logger.logger.instrument('Auto wallet creation abandoned', Object.assign(Object.assign({}, logData), { key: 'auto_wallet_creation_abandoned', reason: 'page_hidden', time: Date.now() - startTime }));
48
+ };
49
+ (_b = globalThis.addEventListener) === null || _b === void 0 ? void 0 : _b.call(globalThis, 'pagehide', handlePageHide);
50
+ try {
51
+ return yield run();
52
+ }
53
+ finally {
54
+ clearTimeout(timeoutId);
55
+ (_c = globalThis.removeEventListener) === null || _c === void 0 ? void 0 : _c.call(globalThis, 'pagehide', handlePageHide);
56
+ }
57
+ });
58
+
59
+ exports.AUTO_WALLET_CREATION_TIMEOUT_MS = AUTO_WALLET_CREATION_TIMEOUT_MS;
60
+ exports.instrumentWalletCreation = instrumentWalletCreation;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Soft watchdog for the embedded-wallet auto-creation ceremony. Long enough to
3
+ * clear a healthy MPC ceremony (observed ~7s, iframe load timeout is 10s) so a
4
+ * fire here means the flow genuinely stalled rather than just being slow.
5
+ */
6
+ export declare const AUTO_WALLET_CREATION_TIMEOUT_MS = 30000;
7
+ type InstrumentWalletCreationArgs<T> = {
8
+ /** The wallet-creation work to run and observe (the MPC ceremony). */
9
+ run: () => Promise<T>;
10
+ /** Shared fields attached to every emitted event (chains, env, user). */
11
+ logData: Record<string, unknown>;
12
+ timeoutMs?: number;
13
+ };
14
+ /**
15
+ * Wraps the auto-wallet-creation ceremony so that "silent" failures carry a
16
+ * reason. Without this, a ceremony that hangs (promise never settles) or a user
17
+ * who navigates away mid-flow produces an `initiated` log with no `success` or
18
+ * `failed` counterpart, leaving the failure undiagnosable.
19
+ *
20
+ * Emits:
21
+ * - `auto_wallet_creation_timeout` if `run` has not settled within `timeoutMs`.
22
+ * - `auto_wallet_creation_abandoned` if the page is hidden while `run` is still
23
+ * in flight (relies on the logger's keepalive transport to survive unload).
24
+ *
25
+ * The watchdog is observational: it never aborts `run`, and its return value /
26
+ * rejection is passed through unchanged.
27
+ */
28
+ export declare const instrumentWalletCreation: <T>({ run, logData, timeoutMs, }: InstrumentWalletCreationArgs<T>) => Promise<T>;
29
+ export {};
@@ -0,0 +1,55 @@
1
+ 'use client'
2
+ import { __awaiter } from '../../../../../_virtual/_tslib.js';
3
+ import '@dynamic-labs/iconic';
4
+ import '@dynamic-labs/wallet-connector-core';
5
+ import 'react';
6
+ import 'react/jsx-runtime';
7
+ import '../../../context/ViewContext/ViewContext.js';
8
+ import { logger } from '../../../shared/logger.js';
9
+ import '@dynamic-labs/wallet-book';
10
+ import '@dynamic-labs/utils';
11
+ import '../../constants/colors.js';
12
+ import '../../constants/values.js';
13
+ import '@dynamic-labs/sdk-api-core';
14
+ import '../../../shared/consts/index.js';
15
+
16
+ /**
17
+ * Soft watchdog for the embedded-wallet auto-creation ceremony. Long enough to
18
+ * clear a healthy MPC ceremony (observed ~7s, iframe load timeout is 10s) so a
19
+ * fire here means the flow genuinely stalled rather than just being slow.
20
+ */
21
+ const AUTO_WALLET_CREATION_TIMEOUT_MS = 30000;
22
+ /**
23
+ * Wraps the auto-wallet-creation ceremony so that "silent" failures carry a
24
+ * reason. Without this, a ceremony that hangs (promise never settles) or a user
25
+ * who navigates away mid-flow produces an `initiated` log with no `success` or
26
+ * `failed` counterpart, leaving the failure undiagnosable.
27
+ *
28
+ * Emits:
29
+ * - `auto_wallet_creation_timeout` if `run` has not settled within `timeoutMs`.
30
+ * - `auto_wallet_creation_abandoned` if the page is hidden while `run` is still
31
+ * in flight (relies on the logger's keepalive transport to survive unload).
32
+ *
33
+ * The watchdog is observational: it never aborts `run`, and its return value /
34
+ * rejection is passed through unchanged.
35
+ */
36
+ const instrumentWalletCreation = (_a) => __awaiter(void 0, [_a], void 0, function* ({ run, logData, timeoutMs = AUTO_WALLET_CREATION_TIMEOUT_MS, }) {
37
+ var _b, _c;
38
+ const startTime = Date.now();
39
+ const timeoutId = setTimeout(() => {
40
+ logger.instrument('Auto wallet creation timed out', Object.assign(Object.assign({}, logData), { key: 'auto_wallet_creation_timeout', reason: 'timeout', time: Date.now() - startTime }));
41
+ }, timeoutMs);
42
+ const handlePageHide = () => {
43
+ logger.instrument('Auto wallet creation abandoned', Object.assign(Object.assign({}, logData), { key: 'auto_wallet_creation_abandoned', reason: 'page_hidden', time: Date.now() - startTime }));
44
+ };
45
+ (_b = globalThis.addEventListener) === null || _b === void 0 ? void 0 : _b.call(globalThis, 'pagehide', handlePageHide);
46
+ try {
47
+ return yield run();
48
+ }
49
+ finally {
50
+ clearTimeout(timeoutId);
51
+ (_c = globalThis.removeEventListener) === null || _c === void 0 ? void 0 : _c.call(globalThis, 'pagehide', handlePageHide);
52
+ }
53
+ });
54
+
55
+ export { AUTO_WALLET_CREATION_TIMEOUT_MS, instrumentWalletCreation };
@@ -41,6 +41,7 @@ var useMutation = require('../useMutation/useMutation.cjs');
41
41
  var useSetupPassword = require('../useSetupPassword/useSetupPassword.cjs');
42
42
  var useWalletDelegation = require('../useWalletDelegation/useWalletDelegation.cjs');
43
43
  require('../useWalletDelegation/DelegationError.cjs');
44
+ var instrumentWalletCreation = require('./instrumentWalletCreation.cjs');
44
45
 
45
46
  // Validate if all required conditions are met for wallet creation
46
47
  const useWalletCreationValidation = () => {
@@ -77,31 +78,28 @@ const useWalletCreation = () => {
77
78
  return useMutation.useMutation((requirements) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
78
79
  const startTime = Date.now();
79
80
  const chainsString = requirements.map((req) => req.chain).join(',');
80
- // Log wallet creation initiation to DataDog
81
- logger.logger.instrument('Auto wallet creation initiated', {
81
+ const baseLogData = {
82
82
  chainCount: requirements.length,
83
83
  chains: chainsString,
84
84
  environmentId,
85
- key: 'auto_wallet_creation_initiated',
86
- time: 0,
87
85
  userId: user === null || user === void 0 ? void 0 : user.id,
88
- });
86
+ };
87
+ // Log wallet creation initiation to DataDog
88
+ logger.logger.instrument('Auto wallet creation initiated', Object.assign(Object.assign({}, baseLogData), { key: 'auto_wallet_creation_initiated', time: 0 }));
89
89
  try {
90
90
  // If passcodeRequired is enabled, prompt user to set up password first
91
91
  const password = yield setupPassword();
92
- yield createWalletAccount(requirements, password, undefined, {
93
- skipCloseAuthFlow: Boolean(password),
92
+ // Wrap the ceremony so a hang or mid-flow page exit emits a reason
93
+ // instead of leaving a silent "initiated" with no resolution.
94
+ yield instrumentWalletCreation.instrumentWalletCreation({
95
+ logData: baseLogData,
96
+ run: () => createWalletAccount(requirements, password, undefined, {
97
+ skipCloseAuthFlow: Boolean(password),
98
+ }),
94
99
  });
95
100
  const duration = Date.now() - startTime;
96
101
  // Log successful wallet creation to DataDog
97
- logger.logger.instrument('Auto wallet creation successful', {
98
- chainCount: requirements.length,
99
- chains: chainsString,
100
- environmentId,
101
- key: 'auto_wallet_creation_success',
102
- time: duration,
103
- userId: user === null || user === void 0 ? void 0 : user.id,
104
- });
102
+ logger.logger.instrument('Auto wallet creation successful', Object.assign(Object.assign({}, baseLogData), { key: 'auto_wallet_creation_success', time: duration }));
105
103
  }
106
104
  catch (error) {
107
105
  const duration = Date.now() - startTime;
@@ -110,15 +108,7 @@ const useWalletCreation = () => {
110
108
  // UI for this case; the metric should be consistent with that intent.
111
109
  if (!(error instanceof Error &&
112
110
  error.message === useSetupPassword.PASSWORD_SETUP_CANCELLED_ERROR)) {
113
- logger.logger.instrument('Auto wallet creation failed', {
114
- chainCount: requirements.length,
115
- chains: chainsString,
116
- environmentId,
117
- error: error instanceof Error ? error.message : 'Unknown error',
118
- key: 'auto_wallet_creation_failed',
119
- time: duration,
120
- userId: user === null || user === void 0 ? void 0 : user.id,
121
- });
111
+ logger.logger.instrument('Auto wallet creation failed', Object.assign(Object.assign({}, baseLogData), { error: error instanceof Error ? error.message : 'Unknown error', key: 'auto_wallet_creation_failed', time: duration }));
122
112
  }
123
113
  throw error;
124
114
  }
@@ -37,6 +37,7 @@ import { useMutation } from '../useMutation/useMutation.js';
37
37
  import { useSetupPassword, PASSWORD_SETUP_CANCELLED_ERROR } from '../useSetupPassword/useSetupPassword.js';
38
38
  import { useWalletDelegation } from '../useWalletDelegation/useWalletDelegation.js';
39
39
  import '../useWalletDelegation/DelegationError.js';
40
+ import { instrumentWalletCreation } from './instrumentWalletCreation.js';
40
41
 
41
42
  // Validate if all required conditions are met for wallet creation
42
43
  const useWalletCreationValidation = () => {
@@ -73,31 +74,28 @@ const useWalletCreation = () => {
73
74
  return useMutation((requirements) => __awaiter(void 0, void 0, void 0, function* () {
74
75
  const startTime = Date.now();
75
76
  const chainsString = requirements.map((req) => req.chain).join(',');
76
- // Log wallet creation initiation to DataDog
77
- logger.instrument('Auto wallet creation initiated', {
77
+ const baseLogData = {
78
78
  chainCount: requirements.length,
79
79
  chains: chainsString,
80
80
  environmentId,
81
- key: 'auto_wallet_creation_initiated',
82
- time: 0,
83
81
  userId: user === null || user === void 0 ? void 0 : user.id,
84
- });
82
+ };
83
+ // Log wallet creation initiation to DataDog
84
+ logger.instrument('Auto wallet creation initiated', Object.assign(Object.assign({}, baseLogData), { key: 'auto_wallet_creation_initiated', time: 0 }));
85
85
  try {
86
86
  // If passcodeRequired is enabled, prompt user to set up password first
87
87
  const password = yield setupPassword();
88
- yield createWalletAccount(requirements, password, undefined, {
89
- skipCloseAuthFlow: Boolean(password),
88
+ // Wrap the ceremony so a hang or mid-flow page exit emits a reason
89
+ // instead of leaving a silent "initiated" with no resolution.
90
+ yield instrumentWalletCreation({
91
+ logData: baseLogData,
92
+ run: () => createWalletAccount(requirements, password, undefined, {
93
+ skipCloseAuthFlow: Boolean(password),
94
+ }),
90
95
  });
91
96
  const duration = Date.now() - startTime;
92
97
  // Log successful wallet creation to DataDog
93
- logger.instrument('Auto wallet creation successful', {
94
- chainCount: requirements.length,
95
- chains: chainsString,
96
- environmentId,
97
- key: 'auto_wallet_creation_success',
98
- time: duration,
99
- userId: user === null || user === void 0 ? void 0 : user.id,
100
- });
98
+ logger.instrument('Auto wallet creation successful', Object.assign(Object.assign({}, baseLogData), { key: 'auto_wallet_creation_success', time: duration }));
101
99
  }
102
100
  catch (error) {
103
101
  const duration = Date.now() - startTime;
@@ -106,15 +104,7 @@ const useWalletCreation = () => {
106
104
  // UI for this case; the metric should be consistent with that intent.
107
105
  if (!(error instanceof Error &&
108
106
  error.message === PASSWORD_SETUP_CANCELLED_ERROR)) {
109
- logger.instrument('Auto wallet creation failed', {
110
- chainCount: requirements.length,
111
- chains: chainsString,
112
- environmentId,
113
- error: error instanceof Error ? error.message : 'Unknown error',
114
- key: 'auto_wallet_creation_failed',
115
- time: duration,
116
- userId: user === null || user === void 0 ? void 0 : user.id,
117
- });
107
+ logger.instrument('Auto wallet creation failed', Object.assign(Object.assign({}, baseLogData), { error: error instanceof Error ? error.message : 'Unknown error', key: 'auto_wallet_creation_failed', time: duration }));
118
108
  }
119
109
  throw error;
120
110
  }
@@ -312,7 +312,23 @@ const TransactionConfirmationView = ({ transaction, onError, onSuccess, mutation
312
312
  if (transaction.fetchFee) {
313
313
  const feePromise = transaction.fetchFee();
314
314
  if (feePromise && typeof feePromise.finally === 'function') {
315
- feePromise.finally(update);
315
+ feePromise.finally(() => {
316
+ // `transaction.isGasSponsored()` is a synchronous getter that
317
+ // reads a flag the transaction caches during `fetchFee`. On
318
+ // Aleo we can't know whether Feemaster covers the call until
319
+ // that async lookup resolves, so the flag starts at `false`
320
+ // and flips to `true` once the policy answer lands. The
321
+ // initial-mount `useEffect` below only runs when
322
+ // `transaction` itself changes, so without re-reading here
323
+ // React's `isGasSponsored` state stays `false` and the
324
+ // confirmation card renders the gas row with a `--` value
325
+ // (since `fee.gas = 0n` for sponsored calls). Re-read once
326
+ // the cached flag is populated so the row hides itself.
327
+ if (transaction.isGasSponsored) {
328
+ setIsGasSponsored(transaction.isGasSponsored());
329
+ }
330
+ update();
331
+ });
316
332
  }
317
333
  }
318
334
  }, [primaryWallet, transaction, update]);
@@ -304,7 +304,23 @@ const TransactionConfirmationView = ({ transaction, onError, onSuccess, mutation
304
304
  if (transaction.fetchFee) {
305
305
  const feePromise = transaction.fetchFee();
306
306
  if (feePromise && typeof feePromise.finally === 'function') {
307
- feePromise.finally(update);
307
+ feePromise.finally(() => {
308
+ // `transaction.isGasSponsored()` is a synchronous getter that
309
+ // reads a flag the transaction caches during `fetchFee`. On
310
+ // Aleo we can't know whether Feemaster covers the call until
311
+ // that async lookup resolves, so the flag starts at `false`
312
+ // and flips to `true` once the policy answer lands. The
313
+ // initial-mount `useEffect` below only runs when
314
+ // `transaction` itself changes, so without re-reading here
315
+ // React's `isGasSponsored` state stays `false` and the
316
+ // confirmation card renders the gas row with a `--` value
317
+ // (since `fee.gas = 0n` for sponsored calls). Re-read once
318
+ // the cached flag is populated so the row hides itself.
319
+ if (transaction.isGasSponsored) {
320
+ setIsGasSponsored(transaction.isGasSponsored());
321
+ }
322
+ update();
323
+ });
308
324
  }
309
325
  }
310
326
  }, [primaryWallet, transaction, update]);