@dynamic-labs/sdk-react-core 4.32.1-preview.0 → 4.32.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 (40) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/package.cjs +2 -2
  3. package/package.js +2 -2
  4. package/package.json +12 -12
  5. package/src/index.cjs +10 -2
  6. package/src/index.d.ts +2 -2
  7. package/src/index.js +4 -2
  8. package/src/lib/client/extension/hooks/useClientState/useClientState.cjs +1 -3
  9. package/src/lib/client/extension/hooks/useClientState/useClientState.js +1 -3
  10. package/src/lib/context/DynamicContext/useDynamicContext/useOverrides/useOverrides.cjs +3 -0
  11. package/src/lib/context/DynamicContext/useDynamicContext/useOverrides/useOverrides.js +3 -0
  12. package/src/lib/context/SocialRedirectContext/hooks/useRedirectSocialHandler/useRedirectSocialHandler.cjs +3 -1
  13. package/src/lib/context/SocialRedirectContext/hooks/useRedirectSocialHandler/useRedirectSocialHandler.js +3 -1
  14. package/src/lib/utils/functions/socialStorage/socialStorage.d.ts +5 -0
  15. package/src/lib/utils/functions/walletListBuilder/utils/applyMultiWalletFilters/applyMultiWalletFilters.cjs +1 -4
  16. package/src/lib/utils/functions/walletListBuilder/utils/applyMultiWalletFilters/applyMultiWalletFilters.js +1 -4
  17. package/src/lib/utils/hooks/index.d.ts +2 -0
  18. package/src/lib/utils/hooks/useGetMfaToken/useGetMfaToken.cjs +2 -18
  19. package/src/lib/utils/hooks/useGetMfaToken/useGetMfaToken.js +3 -19
  20. package/src/lib/utils/hooks/useIsMfaRequiredForAction/index.d.ts +1 -0
  21. package/src/lib/utils/hooks/useIsMfaRequiredForAction/useIsMfaRequiredForAction.cjs +34 -0
  22. package/src/lib/utils/hooks/useIsMfaRequiredForAction/useIsMfaRequiredForAction.d.ts +25 -0
  23. package/src/lib/utils/hooks/useIsMfaRequiredForAction/useIsMfaRequiredForAction.js +30 -0
  24. package/src/lib/utils/hooks/usePromptMfaAuth/usePromptMfaAuth.cjs +36 -5
  25. package/src/lib/utils/hooks/usePromptMfaAuth/usePromptMfaAuth.d.ts +1 -1
  26. package/src/lib/utils/hooks/usePromptMfaAuth/usePromptMfaAuth.js +36 -5
  27. package/src/lib/utils/hooks/useSocialAccounts/useSocialAccounts.cjs +1 -0
  28. package/src/lib/utils/hooks/useSocialAccounts/useSocialAccounts.js +1 -0
  29. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.cjs +2 -1
  30. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.d.ts +2 -0
  31. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.js +2 -1
  32. package/src/lib/utils/hooks/useSyncDynamicWaas/useSyncDynamicWaas.cjs +122 -50
  33. package/src/lib/utils/hooks/useSyncDynamicWaas/useSyncDynamicWaas.d.ts +11 -0
  34. package/src/lib/utils/hooks/useSyncDynamicWaas/useSyncDynamicWaas.js +124 -52
  35. package/src/lib/widgets/DynamicWidget/components/PasskeyCard/PasskeyCard.cjs +8 -1
  36. package/src/lib/widgets/DynamicWidget/components/PasskeyCard/PasskeyCard.js +8 -1
  37. package/src/lib/utils/functions/walletListBuilder/utils/createWalletConnectWalletsFilter/createWalletConnectWalletsFilter.cjs +0 -20
  38. package/src/lib/utils/functions/walletListBuilder/utils/createWalletConnectWalletsFilter/createWalletConnectWalletsFilter.d.ts +0 -6
  39. package/src/lib/utils/functions/walletListBuilder/utils/createWalletConnectWalletsFilter/createWalletConnectWalletsFilter.js +0 -16
  40. package/src/lib/utils/functions/walletListBuilder/utils/createWalletConnectWalletsFilter/index.d.ts +0 -1
@@ -22,7 +22,7 @@ import '@dynamic-labs/multi-wallet';
22
22
  import 'react-international-phone';
23
23
  import '../../../store/state/nonce/nonce.js';
24
24
  import '@dynamic-labs-sdk/client/core';
25
- import '../../../client/client.js';
25
+ import { useDynamicClient } from '../../../client/client.js';
26
26
  import '@dynamic-labs-sdk/client';
27
27
  import '../../../config/ApiEndpoint.js';
28
28
  import '../../../store/state/projectSettings/projectSettings.js';
@@ -105,6 +105,7 @@ const usePromptMfaAuth = () => {
105
105
  const { pushView } = useViewContext();
106
106
  const getUserMfaMethods = useGetUserMfaMethods();
107
107
  const authenticatePasskeyMFA = useAuthenticatePasskeyMFA();
108
+ const dynamicClient = useDynamicClient();
108
109
  const promptMfaAuth = useCallback((props) => __awaiter(void 0, void 0, void 0, function* () {
109
110
  const methods = yield getUserMfaMethods();
110
111
  const allMethods = [
@@ -141,17 +142,47 @@ const usePromptMfaAuth = () => {
141
142
  authenticatePasskeyPromise,
142
143
  createMfaToken: props === null || props === void 0 ? void 0 : props.createMfaToken,
143
144
  });
144
- break;
145
+ // Return the promise so callers can await MFA completion
146
+ return authenticatePasskeyPromise;
145
147
  }
146
- case MFADeviceType.Totp:
148
+ case MFADeviceType.Totp: {
147
149
  pushView('mfa-verification', {
148
150
  createMfaToken: props === null || props === void 0 ? void 0 : props.createMfaToken,
149
151
  });
150
- break;
152
+ // Return a promise that resolves when mfaToken becomes available
153
+ return new Promise((resolve, reject) => {
154
+ const maxAttempts = 50; // Maximum number of retry attempts
155
+ const initialDelay = 100; // Initial delay in milliseconds
156
+ const maxDelay = 5000; // Maximum delay between retries
157
+ let attempts = 0;
158
+ const checkForToken = () => {
159
+ attempts++;
160
+ const mfaToken = dynamicClient === null || dynamicClient === void 0 ? void 0 : dynamicClient.mfaToken;
161
+ if (mfaToken) {
162
+ resolve(mfaToken);
163
+ }
164
+ else if (attempts >= maxAttempts) {
165
+ reject(new Error('MFA token not available after maximum retry attempts'));
166
+ }
167
+ else {
168
+ // Exponential backoff with a maximum delay
169
+ const delay = Math.min(initialDelay * Math.pow(1.5, attempts - 1), maxDelay);
170
+ setTimeout(checkForToken, delay);
171
+ }
172
+ };
173
+ checkForToken();
174
+ });
175
+ }
151
176
  default:
152
177
  throw new Error('Error determining MFA method to use');
153
178
  }
154
- }), [authenticatePasskeyMFA, getUserMfaMethods, pushView, setShowAuthFlow]);
179
+ }), [
180
+ authenticatePasskeyMFA,
181
+ dynamicClient === null || dynamicClient === void 0 ? void 0 : dynamicClient.mfaToken,
182
+ getUserMfaMethods,
183
+ pushView,
184
+ setShowAuthFlow,
185
+ ]);
155
186
  return promptMfaAuth;
156
187
  };
157
188
 
@@ -251,6 +251,7 @@ const useSocialAccounts = () => {
251
251
  }) {
252
252
  return connectSocialAccount({
253
253
  authMode: 'signin',
254
+ isHeadlessSocialSignIn: true,
254
255
  payingWithDynamic,
255
256
  provider,
256
257
  redirectUrl,
@@ -247,6 +247,7 @@ const useSocialAccounts = () => {
247
247
  }) {
248
248
  return connectSocialAccount({
249
249
  authMode: 'signin',
250
+ isHeadlessSocialSignIn: true,
250
251
  payingWithDynamic,
251
252
  provider,
252
253
  redirectUrl,
@@ -372,7 +372,7 @@ const useSocialAuth = ({ onSettled, onError, onFarcasterUrl, }) => {
372
372
  shouldRegisterSessionKeysOnSignin,
373
373
  signInAccount,
374
374
  ]);
375
- const connectSocialAccount = React.useCallback((_d) => _tslib.__awaiter(void 0, [_d], void 0, function* ({ authMode, provider, validator, captchaToken, triggerFundFromExchangeOnSuccess, payingWithDynamic, redirectUrl, telegramAuthToken, showWidgetAfterConnection, }) {
375
+ const connectSocialAccount = React.useCallback((_d) => _tslib.__awaiter(void 0, [_d], void 0, function* ({ authMode, provider, validator, captchaToken, isHeadlessSocialSignIn, payingWithDynamic, triggerFundFromExchangeOnSuccess, redirectUrl, telegramAuthToken, showWidgetAfterConnection, }) {
376
376
  var _e, _f;
377
377
  clearError();
378
378
  setIsProcessing(true);
@@ -405,6 +405,7 @@ const useSocialAuth = ({ onSettled, onError, onFarcasterUrl, }) => {
405
405
  socialStorage.setSocialStorageFor(provider, {
406
406
  captchaToken,
407
407
  codeVerifier: usingPkce ? verifier : undefined,
408
+ isHeadlessSocialSignIn,
408
409
  mode: authMode,
409
410
  payingWithDynamic,
410
411
  showWidgetAfterConnection,
@@ -18,6 +18,8 @@ export type ConnectSocialAccountProps = {
18
18
  showWidgetAfterConnection?: boolean;
19
19
  triggerFundFromExchangeOnSuccess?: ExchangeKeyEnum;
20
20
  payingWithDynamic?: PayWithDynamicProps;
21
+ /** marks the flow as initiated by headless sign-in API */
22
+ isHeadlessSocialSignIn?: boolean;
21
23
  };
22
24
  export declare const useSocialAuth: ({ onSettled, onError, onFarcasterUrl, }: UseSocialAuthProps) => {
23
25
  readonly checkValidProvider: (provider: ProviderEnum, authMode: SocialAuthMode) => boolean;
@@ -368,7 +368,7 @@ const useSocialAuth = ({ onSettled, onError, onFarcasterUrl, }) => {
368
368
  shouldRegisterSessionKeysOnSignin,
369
369
  signInAccount,
370
370
  ]);
371
- const connectSocialAccount = useCallback((_d) => __awaiter(void 0, [_d], void 0, function* ({ authMode, provider, validator, captchaToken, triggerFundFromExchangeOnSuccess, payingWithDynamic, redirectUrl, telegramAuthToken, showWidgetAfterConnection, }) {
371
+ const connectSocialAccount = useCallback((_d) => __awaiter(void 0, [_d], void 0, function* ({ authMode, provider, validator, captchaToken, isHeadlessSocialSignIn, payingWithDynamic, triggerFundFromExchangeOnSuccess, redirectUrl, telegramAuthToken, showWidgetAfterConnection, }) {
372
372
  var _e, _f;
373
373
  clearError();
374
374
  setIsProcessing(true);
@@ -401,6 +401,7 @@ const useSocialAuth = ({ onSettled, onError, onFarcasterUrl, }) => {
401
401
  setSocialStorageFor(provider, {
402
402
  captchaToken,
403
403
  codeVerifier: usingPkce ? verifier : undefined,
404
+ isHeadlessSocialSignIn,
404
405
  mode: authMode,
405
406
  payingWithDynamic,
406
407
  showWidgetAfterConnection,
@@ -25,7 +25,7 @@ require('../../../shared/consts/index.cjs');
25
25
  require('../../../store/state/nonce/nonce.cjs');
26
26
  var projectSettings = require('../../../store/state/projectSettings/projectSettings.cjs');
27
27
  require('../../../locale/locale.cjs');
28
- require('../../../store/state/dynamicContextProps/dynamicContextProps.cjs');
28
+ var dynamicContextProps = require('../../../store/state/dynamicContextProps/dynamicContextProps.cjs');
29
29
  require('../../../store/state/primaryWalletId/primaryWalletId.cjs');
30
30
  require('../../../store/state/connectedWalletsInfo/connectedWalletsInfo.cjs');
31
31
  require('../../../events/dynamicEvents.cjs');
@@ -45,6 +45,7 @@ require('../../functions/compareChains/compareChains.cjs');
45
45
  require('../../../views/Passkey/utils/findPrimaryEmbeddedChain/findPrimaryEmbeddedChain.cjs');
46
46
  require('../../../context/ThemeContext/ThemeContext.cjs');
47
47
  require('../useUserUpdateRequest/useUpdateUser/userFieldsSchema.cjs');
48
+ var useMutation = require('../useMutation/useMutation.cjs');
48
49
  require('bs58');
49
50
  require('@dynamic-labs/types');
50
51
  require('../../../context/SocialRedirectContext/SocialRedirectContext.cjs');
@@ -105,63 +106,134 @@ require('../../../store/state/multichainBalances.cjs');
105
106
  require('../../../shared/utils/functions/getInitialUrl/getInitialUrl.cjs');
106
107
  var useInternalDynamicContext = require('../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.cjs');
107
108
 
108
- const useSyncDynamicWaas = () => {
109
- const { primaryWallet, setShowAuthFlow } = useInternalDynamicContext.useInternalDynamicContext();
110
- const { loading: globalLoading } = LoadingContext.useLoadingContext();
111
- const { clearStackAndPush } = ViewContext.useViewContext();
112
- const user = useOnboardingCompleteUser.useOnboardingCompleteUserProfile();
109
+ // Validate if all required conditions are met for wallet creation
110
+ const useWalletCreationValidation = () => {
111
+ const user = useOnboardingCompleteUser.useOnboardingCompleteUser();
113
112
  const projectSettings$1 = projectSettings.useProjectSettings();
114
113
  const walletConnectorOptions = walletOptions.useWalletConnectorOptions();
115
- const { createWalletAccount, needsAutoCreateWalletChains } = useDynamicWaas.useDynamicWaas();
114
+ const { loading: globalLoading } = LoadingContext.useLoadingContext();
115
+ return React.useCallback(() => {
116
+ // Check if user is properly authenticated
117
+ const hasUser = Boolean(user && client.getDynamicClient().user);
118
+ if (!hasUser) {
119
+ return { isValid: false, reason: 'User not authenticated' };
120
+ }
121
+ if (!projectSettings$1) {
122
+ return { isValid: false, reason: 'Project settings not loaded' };
123
+ }
124
+ if (!walletConnectorOptions.length) {
125
+ return { isValid: false, reason: 'No wallet connectors available' };
126
+ }
127
+ if (globalLoading) {
128
+ return { isValid: false, reason: 'Authentication in progress' };
129
+ }
130
+ return { isValid: true };
131
+ }, [user, projectSettings$1, walletConnectorOptions, globalLoading]);
132
+ };
133
+ // Manage wallet creation with proper error handling
134
+ const useWalletCreation = () => {
135
+ const { setShowAuthFlow } = useInternalDynamicContext.useInternalDynamicContext();
136
+ const { clearStackAndPush } = ViewContext.useViewContext();
137
+ const { createWalletAccount } = useDynamicWaas.useDynamicWaas();
138
+ const user = useOnboardingCompleteUser.useOnboardingCompleteUser();
139
+ const environmentId = dynamicContextProps.useEnvironmentId();
140
+ return useMutation.useMutation((chains) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
141
+ const startTime = Date.now();
142
+ // Log wallet creation initiation to DataDog
143
+ logger.logger.instrument('Auto wallet creation initiated', {
144
+ chainCount: chains.length,
145
+ chains: chains.join(','),
146
+ environmentId,
147
+ key: 'auto_wallet_creation_initiated',
148
+ time: 0,
149
+ userId: user === null || user === void 0 ? void 0 : user.id,
150
+ });
151
+ try {
152
+ yield createWalletAccount(chains);
153
+ const duration = Date.now() - startTime;
154
+ // Log successful wallet creation to DataDog
155
+ logger.logger.instrument('Auto wallet creation successful', {
156
+ chainCount: chains.length,
157
+ chains: chains.join(','),
158
+ environmentId,
159
+ key: 'auto_wallet_creation_success',
160
+ time: duration,
161
+ userId: user === null || user === void 0 ? void 0 : user.id,
162
+ });
163
+ }
164
+ catch (error) {
165
+ const duration = Date.now() - startTime;
166
+ // Log failed wallet creation to DataDog
167
+ logger.logger.instrument('Auto wallet creation failed', {
168
+ chainCount: chains.length,
169
+ chains: chains.join(','),
170
+ environmentId,
171
+ error: error instanceof Error ? error.message : 'Unknown error',
172
+ key: 'auto_wallet_creation_failed',
173
+ time: duration,
174
+ userId: user === null || user === void 0 ? void 0 : user.id,
175
+ });
176
+ throw error;
177
+ }
178
+ }), {
179
+ onFailure: (error) => {
180
+ logger.logger.error('Error creating dynamic waas wallet', error);
181
+ setShowAuthFlow(true);
182
+ clearStackAndPush('backup-unsuccessful');
183
+ },
184
+ });
185
+ };
186
+ /**
187
+ * Hook that synchronizes Dynamic WaaS wallet creation based on user state and configuration.
188
+ *
189
+ * This hook automatically creates embedded wallets for enabled chains when:
190
+ * - User is authenticated and onboarding is complete
191
+ * - Project settings allow automatic wallet creation
192
+ * - Required chains don't already have wallets
193
+ * - No authentication is currently in progress
194
+ *
195
+ * The hook ensures wallet creation only happens once per session until logout.
196
+ */
197
+ const useSyncDynamicWaas = () => {
198
+ const { needsAutoCreateWalletChains } = useDynamicWaas.useDynamicWaas();
199
+ const validateWalletCreation = useWalletCreationValidation();
200
+ const { mutate: createWallets, isLoading: isCreatingWallets } = useWalletCreation();
116
201
  const triggeredCreate = React.useRef(false);
202
+ // Reset the trigger flag on logout
117
203
  useDynamicEvents.useInternalDynamicEvents('logout', () => {
118
204
  triggeredCreate.current = false;
119
205
  });
120
- // this is used to trigger createWalletAccount
121
- // ** It must be an useEffect because some of the dependencies are async
122
- React.useEffect(() => {
123
- // Explanation: if the user just logged out, the user from the hook might still be set
124
- // but the client will be null.
125
- // And if the user is not onboarding complete yet, the hook won't be set even though the client.user is set.
126
- // This is why we check for the user AND the client.user.
127
- const hasUser = Boolean(user && client.getDynamicClient().user);
128
- const syncDynamicWaas = () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
129
- try {
130
- triggeredCreate.current = true;
131
- if (needsAutoCreateWalletChains &&
132
- needsAutoCreateWalletChains.length > 0) {
133
- yield createWalletAccount(needsAutoCreateWalletChains);
134
- }
135
- }
136
- catch (error) {
137
- logger.logger.error('Error creating dynamic waas wallet', error);
138
- setShowAuthFlow(true);
139
- clearStackAndPush('backup-unsuccessful');
140
- }
141
- });
142
- const shouldSyncCreateWallet = needsAutoCreateWalletChains &&
143
- needsAutoCreateWalletChains.length > 0 &&
144
- !triggeredCreate.current;
145
- if (!shouldSyncCreateWallet ||
146
- !hasUser ||
147
- !projectSettings$1 ||
148
- !walletConnectorOptions.length || // no connectors to use for the embedded wallet
149
- globalLoading // this will be true if auth is in progress
150
- ) {
206
+ // Determine if wallet creation should be triggered
207
+ const shouldCreateWallets = React.useCallback(() => {
208
+ if (triggeredCreate.current || isCreatingWallets) {
209
+ return false;
210
+ }
211
+ if (!(needsAutoCreateWalletChains === null || needsAutoCreateWalletChains === void 0 ? void 0 : needsAutoCreateWalletChains.length)) {
212
+ return false;
213
+ }
214
+ const validation = validateWalletCreation();
215
+ return validation.isValid;
216
+ }, [needsAutoCreateWalletChains, validateWalletCreation, isCreatingWallets]);
217
+ // Handle the wallet creation process
218
+ const handleWalletCreation = React.useCallback(() => {
219
+ if (!shouldCreateWallets() || !needsAutoCreateWalletChains) {
151
220
  return;
152
221
  }
153
- syncDynamicWaas();
154
- }, [
155
- user,
156
- projectSettings$1,
157
- walletConnectorOptions,
158
- globalLoading,
159
- setShowAuthFlow,
160
- createWalletAccount,
161
- primaryWallet,
162
- needsAutoCreateWalletChains,
163
- clearStackAndPush,
164
- ]);
222
+ logger.logger.debug('Auto wallet creation triggered', {
223
+ chainCount: needsAutoCreateWalletChains.length,
224
+ chains: needsAutoCreateWalletChains,
225
+ });
226
+ // Call the mutation - it handles its own async logic and error handling
227
+ createWallets(needsAutoCreateWalletChains);
228
+ // Set the flag immediately to prevent duplicate calls
229
+ triggeredCreate.current = true;
230
+ }, [shouldCreateWallets, needsAutoCreateWalletChains, createWallets]);
231
+ // Effect to trigger wallet creation when conditions are met
232
+ React.useEffect(() => {
233
+ if (shouldCreateWallets()) {
234
+ handleWalletCreation();
235
+ }
236
+ }, [shouldCreateWallets, handleWalletCreation]);
165
237
  };
166
238
 
167
239
  exports.useSyncDynamicWaas = useSyncDynamicWaas;
@@ -1 +1,12 @@
1
+ /**
2
+ * Hook that synchronizes Dynamic WaaS wallet creation based on user state and configuration.
3
+ *
4
+ * This hook automatically creates embedded wallets for enabled chains when:
5
+ * - User is authenticated and onboarding is complete
6
+ * - Project settings allow automatic wallet creation
7
+ * - Required chains don't already have wallets
8
+ * - No authentication is currently in progress
9
+ *
10
+ * The hook ensures wallet creation only happens once per session until logout.
11
+ */
1
12
  export declare const useSyncDynamicWaas: () => void;
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../_virtual/_tslib.js';
3
- import { useRef, useEffect } from 'react';
3
+ import { useRef, useCallback, useEffect } from 'react';
4
4
  import { getDynamicClient } from '../../../client/client.js';
5
5
  import '@dynamic-labs-sdk/client/core';
6
6
  import '@dynamic-labs/sdk-api-core';
@@ -21,11 +21,11 @@ import '../../../shared/consts/index.js';
21
21
  import '../../../store/state/nonce/nonce.js';
22
22
  import { useProjectSettings } from '../../../store/state/projectSettings/projectSettings.js';
23
23
  import '../../../locale/locale.js';
24
- import '../../../store/state/dynamicContextProps/dynamicContextProps.js';
24
+ import { useEnvironmentId } from '../../../store/state/dynamicContextProps/dynamicContextProps.js';
25
25
  import '../../../store/state/primaryWalletId/primaryWalletId.js';
26
26
  import '../../../store/state/connectedWalletsInfo/connectedWalletsInfo.js';
27
27
  import '../../../events/dynamicEvents.js';
28
- import { useOnboardingCompleteUserProfile } from '../../../client/extension/user/useOnboardingCompleteUser/useOnboardingCompleteUser.js';
28
+ import { useOnboardingCompleteUser } from '../../../client/extension/user/useOnboardingCompleteUser/useOnboardingCompleteUser.js';
29
29
  import '../../../context/DynamicContext/DynamicContext.js';
30
30
  import '../../../store/state/loadingAndLifecycle/loadingAndLifecycle.js';
31
31
  import { useInternalDynamicEvents } from '../events/useDynamicEvents/useDynamicEvents.js';
@@ -41,6 +41,7 @@ import '../../functions/compareChains/compareChains.js';
41
41
  import '../../../views/Passkey/utils/findPrimaryEmbeddedChain/findPrimaryEmbeddedChain.js';
42
42
  import '../../../context/ThemeContext/ThemeContext.js';
43
43
  import '../useUserUpdateRequest/useUpdateUser/userFieldsSchema.js';
44
+ import { useMutation } from '../useMutation/useMutation.js';
44
45
  import 'bs58';
45
46
  import '@dynamic-labs/types';
46
47
  import '../../../context/SocialRedirectContext/SocialRedirectContext.js';
@@ -101,63 +102,134 @@ import '../../../store/state/multichainBalances.js';
101
102
  import '../../../shared/utils/functions/getInitialUrl/getInitialUrl.js';
102
103
  import { useInternalDynamicContext } from '../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
103
104
 
104
- const useSyncDynamicWaas = () => {
105
- const { primaryWallet, setShowAuthFlow } = useInternalDynamicContext();
106
- const { loading: globalLoading } = useLoadingContext();
107
- const { clearStackAndPush } = useViewContext();
108
- const user = useOnboardingCompleteUserProfile();
105
+ // Validate if all required conditions are met for wallet creation
106
+ const useWalletCreationValidation = () => {
107
+ const user = useOnboardingCompleteUser();
109
108
  const projectSettings = useProjectSettings();
110
109
  const walletConnectorOptions = useWalletConnectorOptions();
111
- const { createWalletAccount, needsAutoCreateWalletChains } = useDynamicWaas();
110
+ const { loading: globalLoading } = useLoadingContext();
111
+ return useCallback(() => {
112
+ // Check if user is properly authenticated
113
+ const hasUser = Boolean(user && getDynamicClient().user);
114
+ if (!hasUser) {
115
+ return { isValid: false, reason: 'User not authenticated' };
116
+ }
117
+ if (!projectSettings) {
118
+ return { isValid: false, reason: 'Project settings not loaded' };
119
+ }
120
+ if (!walletConnectorOptions.length) {
121
+ return { isValid: false, reason: 'No wallet connectors available' };
122
+ }
123
+ if (globalLoading) {
124
+ return { isValid: false, reason: 'Authentication in progress' };
125
+ }
126
+ return { isValid: true };
127
+ }, [user, projectSettings, walletConnectorOptions, globalLoading]);
128
+ };
129
+ // Manage wallet creation with proper error handling
130
+ const useWalletCreation = () => {
131
+ const { setShowAuthFlow } = useInternalDynamicContext();
132
+ const { clearStackAndPush } = useViewContext();
133
+ const { createWalletAccount } = useDynamicWaas();
134
+ const user = useOnboardingCompleteUser();
135
+ const environmentId = useEnvironmentId();
136
+ return useMutation((chains) => __awaiter(void 0, void 0, void 0, function* () {
137
+ const startTime = Date.now();
138
+ // Log wallet creation initiation to DataDog
139
+ logger.instrument('Auto wallet creation initiated', {
140
+ chainCount: chains.length,
141
+ chains: chains.join(','),
142
+ environmentId,
143
+ key: 'auto_wallet_creation_initiated',
144
+ time: 0,
145
+ userId: user === null || user === void 0 ? void 0 : user.id,
146
+ });
147
+ try {
148
+ yield createWalletAccount(chains);
149
+ const duration = Date.now() - startTime;
150
+ // Log successful wallet creation to DataDog
151
+ logger.instrument('Auto wallet creation successful', {
152
+ chainCount: chains.length,
153
+ chains: chains.join(','),
154
+ environmentId,
155
+ key: 'auto_wallet_creation_success',
156
+ time: duration,
157
+ userId: user === null || user === void 0 ? void 0 : user.id,
158
+ });
159
+ }
160
+ catch (error) {
161
+ const duration = Date.now() - startTime;
162
+ // Log failed wallet creation to DataDog
163
+ logger.instrument('Auto wallet creation failed', {
164
+ chainCount: chains.length,
165
+ chains: chains.join(','),
166
+ environmentId,
167
+ error: error instanceof Error ? error.message : 'Unknown error',
168
+ key: 'auto_wallet_creation_failed',
169
+ time: duration,
170
+ userId: user === null || user === void 0 ? void 0 : user.id,
171
+ });
172
+ throw error;
173
+ }
174
+ }), {
175
+ onFailure: (error) => {
176
+ logger.error('Error creating dynamic waas wallet', error);
177
+ setShowAuthFlow(true);
178
+ clearStackAndPush('backup-unsuccessful');
179
+ },
180
+ });
181
+ };
182
+ /**
183
+ * Hook that synchronizes Dynamic WaaS wallet creation based on user state and configuration.
184
+ *
185
+ * This hook automatically creates embedded wallets for enabled chains when:
186
+ * - User is authenticated and onboarding is complete
187
+ * - Project settings allow automatic wallet creation
188
+ * - Required chains don't already have wallets
189
+ * - No authentication is currently in progress
190
+ *
191
+ * The hook ensures wallet creation only happens once per session until logout.
192
+ */
193
+ const useSyncDynamicWaas = () => {
194
+ const { needsAutoCreateWalletChains } = useDynamicWaas();
195
+ const validateWalletCreation = useWalletCreationValidation();
196
+ const { mutate: createWallets, isLoading: isCreatingWallets } = useWalletCreation();
112
197
  const triggeredCreate = useRef(false);
198
+ // Reset the trigger flag on logout
113
199
  useInternalDynamicEvents('logout', () => {
114
200
  triggeredCreate.current = false;
115
201
  });
116
- // this is used to trigger createWalletAccount
117
- // ** It must be an useEffect because some of the dependencies are async
118
- useEffect(() => {
119
- // Explanation: if the user just logged out, the user from the hook might still be set
120
- // but the client will be null.
121
- // And if the user is not onboarding complete yet, the hook won't be set even though the client.user is set.
122
- // This is why we check for the user AND the client.user.
123
- const hasUser = Boolean(user && getDynamicClient().user);
124
- const syncDynamicWaas = () => __awaiter(void 0, void 0, void 0, function* () {
125
- try {
126
- triggeredCreate.current = true;
127
- if (needsAutoCreateWalletChains &&
128
- needsAutoCreateWalletChains.length > 0) {
129
- yield createWalletAccount(needsAutoCreateWalletChains);
130
- }
131
- }
132
- catch (error) {
133
- logger.error('Error creating dynamic waas wallet', error);
134
- setShowAuthFlow(true);
135
- clearStackAndPush('backup-unsuccessful');
136
- }
137
- });
138
- const shouldSyncCreateWallet = needsAutoCreateWalletChains &&
139
- needsAutoCreateWalletChains.length > 0 &&
140
- !triggeredCreate.current;
141
- if (!shouldSyncCreateWallet ||
142
- !hasUser ||
143
- !projectSettings ||
144
- !walletConnectorOptions.length || // no connectors to use for the embedded wallet
145
- globalLoading // this will be true if auth is in progress
146
- ) {
202
+ // Determine if wallet creation should be triggered
203
+ const shouldCreateWallets = useCallback(() => {
204
+ if (triggeredCreate.current || isCreatingWallets) {
205
+ return false;
206
+ }
207
+ if (!(needsAutoCreateWalletChains === null || needsAutoCreateWalletChains === void 0 ? void 0 : needsAutoCreateWalletChains.length)) {
208
+ return false;
209
+ }
210
+ const validation = validateWalletCreation();
211
+ return validation.isValid;
212
+ }, [needsAutoCreateWalletChains, validateWalletCreation, isCreatingWallets]);
213
+ // Handle the wallet creation process
214
+ const handleWalletCreation = useCallback(() => {
215
+ if (!shouldCreateWallets() || !needsAutoCreateWalletChains) {
147
216
  return;
148
217
  }
149
- syncDynamicWaas();
150
- }, [
151
- user,
152
- projectSettings,
153
- walletConnectorOptions,
154
- globalLoading,
155
- setShowAuthFlow,
156
- createWalletAccount,
157
- primaryWallet,
158
- needsAutoCreateWalletChains,
159
- clearStackAndPush,
160
- ]);
218
+ logger.debug('Auto wallet creation triggered', {
219
+ chainCount: needsAutoCreateWalletChains.length,
220
+ chains: needsAutoCreateWalletChains,
221
+ });
222
+ // Call the mutation - it handles its own async logic and error handling
223
+ createWallets(needsAutoCreateWalletChains);
224
+ // Set the flag immediately to prevent duplicate calls
225
+ triggeredCreate.current = true;
226
+ }, [shouldCreateWallets, needsAutoCreateWalletChains, createWallets]);
227
+ // Effect to trigger wallet creation when conditions are met
228
+ useEffect(() => {
229
+ if (shouldCreateWallets()) {
230
+ handleWalletCreation();
231
+ }
232
+ }, [shouldCreateWallets, handleWalletCreation]);
161
233
  };
162
234
 
163
235
  export { useSyncDynamicWaas };
@@ -8,10 +8,10 @@ var jsxRuntime = require('react/jsx-runtime');
8
8
  var React = require('react');
9
9
  var reactI18next = require('react-i18next');
10
10
  var iconic = require('@dynamic-labs/iconic');
11
+ var sdkApiCore = require('@dynamic-labs/sdk-api-core');
11
12
  var Typography = require('../../../../components/Typography/Typography.cjs');
12
13
  require('../../../../context/DynamicContext/DynamicContext.cjs');
13
14
  require('../../../../store/state/loadingAndLifecycle/loadingAndLifecycle.cjs');
14
- require('@dynamic-labs/sdk-api-core');
15
15
  require('../../../../shared/logger.cjs');
16
16
  require('@dynamic-labs/wallet-connector-core');
17
17
  var ViewContext = require('../../../../context/ViewContext/ViewContext.cjs');
@@ -104,9 +104,11 @@ require('../../../../../index.cjs');
104
104
  require('../../views/ReceiveWalletFunds/ReceiveWalletFunds.cjs');
105
105
  require('../../../../store/state/tokenBalances.cjs');
106
106
  require('../../../../store/state/multichainBalances.cjs');
107
+ var usePromptMfaAuth = require('../../../../utils/hooks/usePromptMfaAuth/usePromptMfaAuth.cjs');
107
108
  require('../../../../shared/utils/functions/getInitialUrl/getInitialUrl.cjs');
108
109
  var useDeletePasskey = require('../../../../utils/hooks/useDeletePasskey/useDeletePasskey.cjs');
109
110
  var useInternalDynamicContext = require('../../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.cjs');
111
+ var isMfaMethodEnabled = require('../../../../utils/functions/isMfaMethodEnabled/isMfaMethodEnabled.cjs');
110
112
 
111
113
  const mapPasskeyProviderToIcon = {
112
114
  android: jsxRuntime.jsx(iconic.AndroidIcon, {}),
@@ -125,6 +127,7 @@ const PasskeyCard = ({ passkey, onUpdate }) => {
125
127
  const { pushView } = ViewContext.useViewContext();
126
128
  const { setPasskey, setPasskeyIcon } = PasskeyContext.usePasskeyContext();
127
129
  const deletePasskey = useDeletePasskey.useDeletePasskey();
130
+ const promptMfaAuth = usePromptMfaAuth.usePromptMfaAuth();
128
131
  const menuOptions = [
129
132
  {
130
133
  Icon: null,
@@ -140,6 +143,10 @@ const PasskeyCard = ({ passkey, onUpdate }) => {
140
143
  {
141
144
  Icon: null,
142
145
  callback: () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
146
+ const isMfaRequired = isMfaMethodEnabled.isMfaMethodEnabled(sdkApiCore.MFADeviceType.Passkey);
147
+ if (isMfaRequired) {
148
+ yield promptMfaAuth({ createMfaToken: true });
149
+ }
143
150
  yield deletePasskey(passkey.id);
144
151
  onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate();
145
152
  }),
@@ -4,10 +4,10 @@ import { jsx, jsxs } from 'react/jsx-runtime';
4
4
  import { useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { AndroidIcon, BraveIcon, ChromeIcon, EdgeIcon, FirefoxIcon, AppleIcon, OperaIcon, SafariIcon } from '@dynamic-labs/iconic';
7
+ import { MFADeviceType } from '@dynamic-labs/sdk-api-core';
7
8
  import { Typography } from '../../../../components/Typography/Typography.js';
8
9
  import '../../../../context/DynamicContext/DynamicContext.js';
9
10
  import '../../../../store/state/loadingAndLifecycle/loadingAndLifecycle.js';
10
- import '@dynamic-labs/sdk-api-core';
11
11
  import '../../../../shared/logger.js';
12
12
  import '@dynamic-labs/wallet-connector-core';
13
13
  import { useViewContext } from '../../../../context/ViewContext/ViewContext.js';
@@ -100,9 +100,11 @@ import '../../../../../index.js';
100
100
  import '../../views/ReceiveWalletFunds/ReceiveWalletFunds.js';
101
101
  import '../../../../store/state/tokenBalances.js';
102
102
  import '../../../../store/state/multichainBalances.js';
103
+ import { usePromptMfaAuth } from '../../../../utils/hooks/usePromptMfaAuth/usePromptMfaAuth.js';
103
104
  import '../../../../shared/utils/functions/getInitialUrl/getInitialUrl.js';
104
105
  import { useDeletePasskey } from '../../../../utils/hooks/useDeletePasskey/useDeletePasskey.js';
105
106
  import { useInternalDynamicContext } from '../../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
107
+ import { isMfaMethodEnabled } from '../../../../utils/functions/isMfaMethodEnabled/isMfaMethodEnabled.js';
106
108
 
107
109
  const mapPasskeyProviderToIcon = {
108
110
  android: jsx(AndroidIcon, {}),
@@ -121,6 +123,7 @@ const PasskeyCard = ({ passkey, onUpdate }) => {
121
123
  const { pushView } = useViewContext();
122
124
  const { setPasskey, setPasskeyIcon } = usePasskeyContext();
123
125
  const deletePasskey = useDeletePasskey();
126
+ const promptMfaAuth = usePromptMfaAuth();
124
127
  const menuOptions = [
125
128
  {
126
129
  Icon: null,
@@ -136,6 +139,10 @@ const PasskeyCard = ({ passkey, onUpdate }) => {
136
139
  {
137
140
  Icon: null,
138
141
  callback: () => __awaiter(void 0, void 0, void 0, function* () {
142
+ const isMfaRequired = isMfaMethodEnabled(MFADeviceType.Passkey);
143
+ if (isMfaRequired) {
144
+ yield promptMfaAuth({ createMfaToken: true });
145
+ }
139
146
  yield deletePasskey(passkey.id);
140
147
  onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate();
141
148
  }),