@openfort/react-native 0.1.24 → 0.1.26

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.
@@ -96,7 +96,7 @@ import { buildRecoveryParams } from './utils';
96
96
  * ```
97
97
  */
98
98
  export function useEmbeddedEthereumWallet(options = {}) {
99
- const { client, supportedChains, walletConfig, embeddedState } = useOpenfortContext();
99
+ const { client, supportedChains, walletConfig, embeddedState, user } = useOpenfortContext();
100
100
  const [embeddedAccounts, setEmbeddedAccounts] = useState([]);
101
101
  const [activeWalletId, setActiveWalletId] = useState(null);
102
102
  const [activeAccount, setActiveAccount] = useState(null);
@@ -106,12 +106,16 @@ export function useEmbeddedEthereumWallet(options = {}) {
106
106
  status: 'idle',
107
107
  });
108
108
  // Fetch Ethereum embedded accounts
109
- const fetchEmbeddedAccounts = useCallback(async () => {
109
+ const fetchEmbeddedAccounts = useCallback(async (options) => {
110
110
  if (!client || embeddedState === EmbeddedState.NONE || embeddedState === EmbeddedState.UNAUTHENTICATED) {
111
111
  setEmbeddedAccounts([]);
112
112
  return;
113
113
  }
114
114
  try {
115
+ // Only set fetching status if not called silently (e.g., during create/setActive)
116
+ if (!options?.silent) {
117
+ setStatus({ status: 'fetching-wallets' });
118
+ }
115
119
  const accounts = await client.embeddedWallet.list({
116
120
  limit: 100,
117
121
  chainType: ChainTypeEnum.EVM,
@@ -119,9 +123,15 @@ export function useEmbeddedEthereumWallet(options = {}) {
119
123
  });
120
124
  // Filter for Ethereum accounts only
121
125
  setEmbeddedAccounts(accounts);
126
+ if (!options?.silent) {
127
+ setStatus({ status: 'idle' });
128
+ }
122
129
  }
123
130
  catch {
124
131
  setEmbeddedAccounts([]);
132
+ if (!options?.silent) {
133
+ setStatus({ status: 'idle' });
134
+ }
125
135
  }
126
136
  }, [client, embeddedState, walletConfig]);
127
137
  useEffect(() => {
@@ -250,7 +260,7 @@ export function useEmbeddedEthereumWallet(options = {}) {
250
260
  throw new OpenfortError('No supported chains available for wallet creation', OpenfortErrorType.WALLET_ERROR);
251
261
  }
252
262
  // Build recovery params
253
- const recoveryParams = await buildRecoveryParams(createOptions, walletConfig);
263
+ const recoveryParams = await buildRecoveryParams({ ...createOptions, userId: user?.id }, walletConfig);
254
264
  const accountType = createOptions?.accountType || walletConfig?.accountType || AccountTypeEnum.SMART_ACCOUNT;
255
265
  // Create embedded wallet
256
266
  const embeddedAccount = await client.embeddedWallet.create({
@@ -263,8 +273,8 @@ export function useEmbeddedEthereumWallet(options = {}) {
263
273
  // Get provider
264
274
  const ethProvider = await getEthereumProvider();
265
275
  setProvider(ethProvider);
266
- // Refresh accounts and set as active
267
- await fetchEmbeddedAccounts();
276
+ // Refresh accounts silently (don't override 'creating' status) and set as active
277
+ await fetchEmbeddedAccounts({ silent: true });
268
278
  setActiveWalletId(embeddedAccount.id);
269
279
  setActiveAccount(embeddedAccount);
270
280
  setStatus({ status: 'success' });
@@ -300,7 +310,7 @@ export function useEmbeddedEthereumWallet(options = {}) {
300
310
  }
301
311
  throw error;
302
312
  }
303
- }, [client, supportedChains, walletConfig, options, getEthereumProvider, fetchEmbeddedAccounts]);
313
+ }, [client, supportedChains, walletConfig, options, getEthereumProvider, fetchEmbeddedAccounts, user]);
304
314
  // Set active wallet action
305
315
  const setActive = useCallback(async (setActiveOptions) => {
306
316
  // Prevent concurrent recoveries
@@ -356,7 +366,7 @@ export function useEmbeddedEthereumWallet(options = {}) {
356
366
  throw new OpenfortError(errorMsg, OpenfortErrorType.WALLET_ERROR);
357
367
  }
358
368
  // Build recovery params
359
- const recoveryParams = await buildRecoveryParams(setActiveOptions, walletConfig);
369
+ const recoveryParams = await buildRecoveryParams({ ...setActiveOptions, userId: user?.id }, walletConfig);
360
370
  // Recover the embedded wallet
361
371
  const embeddedAccount = await client.embeddedWallet.recover({
362
372
  account: embeddedAccountToRecover.id,
@@ -415,7 +425,7 @@ export function useEmbeddedEthereumWallet(options = {}) {
415
425
  }
416
426
  })();
417
427
  await recoverPromiseRef.current;
418
- }, [client, supportedChains, walletConfig, embeddedAccounts, options, wallets.length, getEthereumProvider]);
428
+ }, [client, supportedChains, walletConfig, embeddedAccounts, options, wallets.length, getEthereumProvider, user]);
419
429
  // Set recovery method action
420
430
  const setRecovery = useCallback(async (params) => {
421
431
  try {
@@ -476,6 +486,9 @@ export function useEmbeddedEthereumWallet(options = {}) {
476
486
  exportPrivateKey: client.embeddedWallet.exportPrivateKey,
477
487
  };
478
488
  // Priority 1: Explicit action states (user-initiated operations)
489
+ if (status.status === 'fetching-wallets') {
490
+ return { ...baseActions, status: 'fetching-wallets', activeWallet: null };
491
+ }
479
492
  if (status.status === 'creating') {
480
493
  return { ...baseActions, status: 'creating', activeWallet: null };
481
494
  }
@@ -107,7 +107,7 @@ import { buildRecoveryParams } from './utils';
107
107
  * ```
108
108
  */
109
109
  export function useEmbeddedSolanaWallet(options = {}) {
110
- const { client, walletConfig, embeddedState } = useOpenfortContext();
110
+ const { client, walletConfig, embeddedState, user } = useOpenfortContext();
111
111
  const [embeddedAccounts, setEmbeddedAccounts] = useState([]);
112
112
  const [activeWalletId, setActiveWalletId] = useState(null);
113
113
  const [activeAccount, setActiveAccount] = useState(null);
@@ -117,21 +117,31 @@ export function useEmbeddedSolanaWallet(options = {}) {
117
117
  status: 'idle',
118
118
  });
119
119
  // Fetch Solana embedded accounts
120
- const fetchEmbeddedAccounts = useCallback(async () => {
120
+ const fetchEmbeddedAccounts = useCallback(async (options) => {
121
121
  if (!client || embeddedState === EmbeddedState.NONE || embeddedState === EmbeddedState.UNAUTHENTICATED) {
122
122
  setEmbeddedAccounts([]);
123
123
  return;
124
124
  }
125
125
  try {
126
+ // Only set fetching status if not called silently (e.g., during create/setActive)
127
+ if (!options?.silent) {
128
+ setStatus({ status: 'fetching-wallets' });
129
+ }
126
130
  const accounts = await client.embeddedWallet.list({
127
131
  chainType: ChainTypeEnum.SVM,
128
132
  accountType: AccountTypeEnum.EOA,
129
133
  limit: 100,
130
134
  });
131
135
  setEmbeddedAccounts(accounts);
136
+ if (!options?.silent) {
137
+ setStatus({ status: 'idle' });
138
+ }
132
139
  }
133
140
  catch {
134
141
  setEmbeddedAccounts([]);
142
+ if (!options?.silent) {
143
+ setStatus({ status: 'idle' });
144
+ }
135
145
  }
136
146
  }, [client, embeddedState]);
137
147
  useEffect(() => {
@@ -266,8 +276,10 @@ export function useEmbeddedSolanaWallet(options = {}) {
266
276
  logger.info('Creating Solana wallet with options', createOptions);
267
277
  try {
268
278
  setStatus({ status: 'creating' });
269
- // Build recovery params (only use recoveryPassword, ignore createAdditional)
270
- const recoveryParams = await buildRecoveryParams(createOptions?.recoveryPassword ? { recoveryPassword: createOptions.recoveryPassword } : undefined, walletConfig);
279
+ // Build recovery params (only use recoveryPassword, otpCode, and userId, ignore createAdditional)
280
+ const recoveryParams = await buildRecoveryParams(createOptions?.recoveryPassword || createOptions?.otpCode || user?.id
281
+ ? { recoveryPassword: createOptions?.recoveryPassword, otpCode: createOptions?.otpCode, userId: user?.id }
282
+ : undefined, walletConfig);
271
283
  // Create embedded wallet
272
284
  const embeddedAccount = await client.embeddedWallet.create({
273
285
  chainType: ChainTypeEnum.SVM,
@@ -278,8 +290,8 @@ export function useEmbeddedSolanaWallet(options = {}) {
278
290
  // Get provider
279
291
  const solProvider = await getSolanaProvider(embeddedAccount);
280
292
  setProvider(solProvider);
281
- // Refresh accounts and set as active
282
- await fetchEmbeddedAccounts();
293
+ // Refresh accounts silently (don't override 'creating' status) and set as active
294
+ await fetchEmbeddedAccounts({ silent: true });
283
295
  setActiveWalletId(embeddedAccount.id);
284
296
  setActiveAccount(embeddedAccount);
285
297
  setStatus({ status: 'success' });
@@ -315,7 +327,7 @@ export function useEmbeddedSolanaWallet(options = {}) {
315
327
  }
316
328
  throw error;
317
329
  }
318
- }, [client, walletConfig, options, getSolanaProvider, fetchEmbeddedAccounts]);
330
+ }, [client, walletConfig, options, getSolanaProvider, fetchEmbeddedAccounts, user]);
319
331
  // Set active wallet action
320
332
  const setActive = useCallback(async (setActiveOptions) => {
321
333
  // Prevent concurrent recoveries
@@ -346,7 +358,7 @@ export function useEmbeddedSolanaWallet(options = {}) {
346
358
  throw new OpenfortError(`No embedded Solana account found for address ${setActiveOptions.address}`, OpenfortErrorType.WALLET_ERROR);
347
359
  }
348
360
  // Build recovery params
349
- const recoveryParams = await buildRecoveryParams(setActiveOptions, walletConfig);
361
+ const recoveryParams = await buildRecoveryParams({ ...setActiveOptions, userId: user?.id }, walletConfig);
350
362
  // Recover the embedded wallet
351
363
  const embeddedAccount = await client.embeddedWallet.recover({
352
364
  account: embeddedAccountToRecover.id,
@@ -402,7 +414,7 @@ export function useEmbeddedSolanaWallet(options = {}) {
402
414
  }
403
415
  })();
404
416
  await recoverPromiseRef.current;
405
- }, [client, walletConfig, embeddedAccounts, options, wallets.length, getSolanaProvider]);
417
+ }, [client, walletConfig, embeddedAccounts, options, wallets.length, getSolanaProvider, user]);
406
418
  // Build active wallet from embeddedWallet.get()
407
419
  const activeWallet = useMemo(() => {
408
420
  if (!activeWalletId || !activeAccount)
@@ -424,6 +436,9 @@ export function useEmbeddedSolanaWallet(options = {}) {
424
436
  setActive,
425
437
  };
426
438
  // Priority 1: Explicit action states (user-initiated operations)
439
+ if (status.status === 'fetching-wallets') {
440
+ return { ...baseActions, status: 'fetching-wallets', activeWallet: null };
441
+ }
427
442
  if (status.status === 'creating') {
428
443
  return { ...baseActions, status: 'creating', activeWallet: null };
429
444
  }
@@ -7,18 +7,20 @@ import { OpenfortError, OpenfortErrorType } from '../../types/openfortError';
7
7
  * It supports both callback-based session retrieval and endpoint-based session creation.
8
8
  *
9
9
  * @param walletConfig - The embedded wallet configuration from the provider
10
+ * @param otpCode - Optional OTP code for Shield verification
11
+ * @param userId - Optional user ID for the encryption session
10
12
  * @returns A promise that resolves to the encryption session string
11
13
  * @throws {OpenfortError} When wallet config is missing or session cannot be retrieved
12
14
  *
13
15
  * @internal
14
16
  */
15
- async function resolveEncryptionSession(walletConfig) {
17
+ async function resolveEncryptionSession(walletConfig, otpCode, userId) {
16
18
  if (!walletConfig) {
17
19
  throw new OpenfortError('Encryption session configuration is required', OpenfortErrorType.WALLET_ERROR);
18
20
  }
19
21
  // Try callback-based session retrieval first
20
22
  if (walletConfig.getEncryptionSession) {
21
- return await walletConfig.getEncryptionSession();
23
+ return await walletConfig.getEncryptionSession({ otpCode, userId });
22
24
  }
23
25
  // Try endpoint-based session creation
24
26
  if (walletConfig.createEncryptedSessionEndpoint) {
@@ -28,6 +30,7 @@ async function resolveEncryptionSession(walletConfig) {
28
30
  headers: {
29
31
  'Content-Type': 'application/json',
30
32
  },
33
+ body: JSON.stringify({ otp_code: otpCode, user_id: userId }),
31
34
  });
32
35
  if (!response.ok) {
33
36
  throw new OpenfortError('Failed to create encryption session', OpenfortErrorType.WALLET_ERROR, {
@@ -55,7 +58,7 @@ async function resolveEncryptionSession(walletConfig) {
55
58
  * This utility constructs the appropriate RecoveryParams object based on whether
56
59
  * a recovery password is provided or automatic recovery should be used.
57
60
  *
58
- * @param options - Options containing optional recovery password
61
+ * @param options - Options containing optional recovery password, OTP code, and/or user ID
59
62
  * @param walletConfig - The embedded wallet configuration from the provider
60
63
  * @returns A promise that resolves to RecoveryParams for the SDK
61
64
  *
@@ -70,6 +73,6 @@ export async function buildRecoveryParams(options, walletConfig) {
70
73
  }
71
74
  return {
72
75
  recoveryMethod: RecoveryMethod.AUTOMATIC,
73
- encryptionSession: await resolveEncryptionSession(walletConfig),
76
+ encryptionSession: await resolveEncryptionSession(walletConfig, options?.otpCode, options?.userId),
74
77
  };
75
78
  }
@@ -3,6 +3,6 @@ export { RecoveryMethod } from '@openfort/openfort-js';
3
3
  export { createOpenfortClient } from './client';
4
4
  export type { OpenfortContextValue } from './context';
5
5
  export { isOpenfortContextValue, OpenfortContext, useOpenfortContext, useOpenfortContextSafe } from './context';
6
- export type { CommonEmbeddedWalletConfiguration, EmbeddedWalletConfiguration, EncryptionSession, OpenfortProviderProps, } from './provider';
6
+ export type { CommonEmbeddedWalletConfiguration, EmbeddedWalletConfiguration, EncryptionSession, EncryptionSessionParams, OpenfortProviderProps, } from './provider';
7
7
  export { OpenfortProvider } from './provider';
8
8
  export { createNormalizedStorage, SecureStorageAdapter } from './storage';
@@ -11,9 +11,18 @@ export type CommonEmbeddedWalletConfiguration = {
11
11
  /** Recovery method for the embedded wallet: 'automatic' or 'password' */
12
12
  recoveryMethod?: 'automatic' | 'password';
13
13
  };
14
+ /**
15
+ * Parameters passed to the encryption session callback
16
+ */
17
+ export type EncryptionSessionParams = {
18
+ /** OTP code for Shield verification (if required) */
19
+ otpCode?: string;
20
+ /** User ID for the encryption session */
21
+ userId?: string;
22
+ };
14
23
  export type EncryptionSession = {
15
- /** Function to retrieve an encryption session using a session ID */
16
- getEncryptionSession?: () => Promise<string>;
24
+ /** Function to retrieve an encryption session, optionally with OTP verification */
25
+ getEncryptionSession?: (params?: EncryptionSessionParams) => Promise<string>;
17
26
  createEncryptedSessionEndpoint?: never;
18
27
  } | {
19
28
  /** API endpoint for creating an encrypted session */
@@ -6,7 +6,7 @@ import type { EmbeddedWalletConfiguration } from '../../core/provider';
6
6
  * This utility constructs the appropriate RecoveryParams object based on whether
7
7
  * a recovery password is provided or automatic recovery should be used.
8
8
  *
9
- * @param options - Options containing optional recovery password
9
+ * @param options - Options containing optional recovery password, OTP code, and/or user ID
10
10
  * @param walletConfig - The embedded wallet configuration from the provider
11
11
  * @returns A promise that resolves to RecoveryParams for the SDK
12
12
  *
@@ -14,4 +14,6 @@ import type { EmbeddedWalletConfiguration } from '../../core/provider';
14
14
  */
15
15
  export declare function buildRecoveryParams(options: {
16
16
  recoveryPassword?: string;
17
+ otpCode?: string;
18
+ userId?: string;
17
19
  } | undefined, walletConfig?: EmbeddedWalletConfiguration): Promise<RecoveryParams>;
@@ -135,6 +135,8 @@ export type CreateEthereumWalletResult = {
135
135
  export type CreateEthereumWalletOptions = {
136
136
  chainId?: number;
137
137
  recoveryPassword?: string;
138
+ /** OTP code for Shield verification when using automatic recovery */
139
+ otpCode?: string;
138
140
  accountType?: AccountTypeEnum;
139
141
  policyId?: string;
140
142
  } & OpenfortHookOptions<CreateEthereumWalletResult>;
@@ -153,6 +155,8 @@ export type SetActiveEthereumWalletOptions = {
153
155
  address: Hex;
154
156
  chainId?: number;
155
157
  recoveryPassword?: string;
158
+ /** OTP code for Shield verification when using automatic recovery */
159
+ otpCode?: string;
156
160
  } & OpenfortHookOptions<SetActiveEthereumWalletResult>;
157
161
  /**
158
162
  * Result of setting recovery method
@@ -176,6 +180,10 @@ export type CreateSolanaEmbeddedWalletOpts = {
176
180
  * If omitted, automatic recovery will be used.
177
181
  */
178
182
  recoveryPassword?: string;
183
+ /**
184
+ * OTP code for Shield verification when using automatic recovery
185
+ */
186
+ otpCode?: string;
179
187
  /**
180
188
  * Create additional wallet if one already exists
181
189
  */
@@ -207,6 +215,8 @@ export type SetActiveSolanaWalletResult = {
207
215
  export type SetActiveSolanaWalletOptions = {
208
216
  address: string;
209
217
  recoveryPassword?: string;
218
+ /** OTP code for Shield verification when using automatic recovery */
219
+ otpCode?: string;
210
220
  } & OpenfortHookOptions<SetActiveSolanaWalletResult>;
211
221
  /**
212
222
  * Common actions available on all Ethereum wallet states
@@ -256,6 +266,9 @@ export interface SolanaWalletActions {
256
266
  export type EmbeddedEthereumWalletState = (EthereumWalletActions & {
257
267
  status: 'disconnected';
258
268
  activeWallet: null;
269
+ }) | (EthereumWalletActions & {
270
+ status: 'fetching-wallets';
271
+ activeWallet: null;
259
272
  }) | (EthereumWalletActions & {
260
273
  status: 'connecting';
261
274
  activeWallet: ConnectedEmbeddedEthereumWallet;
@@ -283,6 +296,9 @@ export type EmbeddedEthereumWalletState = (EthereumWalletActions & {
283
296
  export type EmbeddedSolanaWalletState = (SolanaWalletActions & {
284
297
  status: 'disconnected';
285
298
  activeWallet: null;
299
+ }) | (SolanaWalletActions & {
300
+ status: 'fetching-wallets';
301
+ activeWallet: null;
286
302
  }) | (SolanaWalletActions & {
287
303
  status: 'connecting';
288
304
  }) | (SolanaWalletActions & {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openfort/react-native",
3
3
  "main": "dist/index.js",
4
- "version": "0.1.24",
4
+ "version": "0.1.26",
5
5
  "license": "MIT",
6
6
  "description": "React Native SDK for Openfort platform integration",
7
7
  "types": "dist/types/index.d.ts",