@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.
- package/CHANGELOG.md +9 -1
- package/package.cjs +2 -2
- package/package.js +2 -2
- package/package.json +12 -12
- package/src/index.cjs +10 -2
- package/src/index.d.ts +2 -2
- package/src/index.js +4 -2
- package/src/lib/client/extension/hooks/useClientState/useClientState.cjs +1 -3
- package/src/lib/client/extension/hooks/useClientState/useClientState.js +1 -3
- package/src/lib/context/DynamicContext/useDynamicContext/useOverrides/useOverrides.cjs +3 -0
- package/src/lib/context/DynamicContext/useDynamicContext/useOverrides/useOverrides.js +3 -0
- package/src/lib/context/SocialRedirectContext/hooks/useRedirectSocialHandler/useRedirectSocialHandler.cjs +3 -1
- package/src/lib/context/SocialRedirectContext/hooks/useRedirectSocialHandler/useRedirectSocialHandler.js +3 -1
- package/src/lib/utils/functions/socialStorage/socialStorage.d.ts +5 -0
- package/src/lib/utils/functions/walletListBuilder/utils/applyMultiWalletFilters/applyMultiWalletFilters.cjs +1 -4
- package/src/lib/utils/functions/walletListBuilder/utils/applyMultiWalletFilters/applyMultiWalletFilters.js +1 -4
- package/src/lib/utils/hooks/index.d.ts +2 -0
- package/src/lib/utils/hooks/useGetMfaToken/useGetMfaToken.cjs +2 -18
- package/src/lib/utils/hooks/useGetMfaToken/useGetMfaToken.js +3 -19
- package/src/lib/utils/hooks/useIsMfaRequiredForAction/index.d.ts +1 -0
- package/src/lib/utils/hooks/useIsMfaRequiredForAction/useIsMfaRequiredForAction.cjs +34 -0
- package/src/lib/utils/hooks/useIsMfaRequiredForAction/useIsMfaRequiredForAction.d.ts +25 -0
- package/src/lib/utils/hooks/useIsMfaRequiredForAction/useIsMfaRequiredForAction.js +30 -0
- package/src/lib/utils/hooks/usePromptMfaAuth/usePromptMfaAuth.cjs +36 -5
- package/src/lib/utils/hooks/usePromptMfaAuth/usePromptMfaAuth.d.ts +1 -1
- package/src/lib/utils/hooks/usePromptMfaAuth/usePromptMfaAuth.js +36 -5
- package/src/lib/utils/hooks/useSocialAccounts/useSocialAccounts.cjs +1 -0
- package/src/lib/utils/hooks/useSocialAccounts/useSocialAccounts.js +1 -0
- package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.cjs +2 -1
- package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.d.ts +2 -0
- package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.js +2 -1
- package/src/lib/utils/hooks/useSyncDynamicWaas/useSyncDynamicWaas.cjs +122 -50
- package/src/lib/utils/hooks/useSyncDynamicWaas/useSyncDynamicWaas.d.ts +11 -0
- package/src/lib/utils/hooks/useSyncDynamicWaas/useSyncDynamicWaas.js +124 -52
- package/src/lib/widgets/DynamicWidget/components/PasskeyCard/PasskeyCard.cjs +8 -1
- package/src/lib/widgets/DynamicWidget/components/PasskeyCard/PasskeyCard.js +8 -1
- package/src/lib/utils/functions/walletListBuilder/utils/createWalletConnectWalletsFilter/createWalletConnectWalletsFilter.cjs +0 -20
- package/src/lib/utils/functions/walletListBuilder/utils/createWalletConnectWalletsFilter/createWalletConnectWalletsFilter.d.ts +0 -6
- package/src/lib/utils/functions/walletListBuilder/utils/createWalletConnectWalletsFilter/createWalletConnectWalletsFilter.js +0 -16
- 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
|
-
|
|
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
|
-
|
|
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
|
-
}), [
|
|
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
|
|
|
@@ -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,
|
|
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,
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
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 {
|
|
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
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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 {
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
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 {
|
|
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
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
}),
|