@phantom/react-native-sdk 1.0.0-beta.1 → 1.0.0-beta.10

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/README.md CHANGED
@@ -89,12 +89,9 @@ export default function App() {
89
89
  return (
90
90
  <PhantomProvider
91
91
  config={{
92
- appId: "your-app-id",
92
+ appId: "your-app-id", // Get your app ID from phantom.com/portal
93
93
  scheme: "mywalletapp", // Must match app.json scheme
94
- embeddedWalletType: "user-wallet",
95
94
  addressTypes: [AddressType.solana],
96
- apiBaseUrl: "https://api.phantom.app/v1/wallets",
97
- solanaProvider: "web3js",
98
95
  authOptions: {
99
96
  redirectUrl: "mywalletapp://phantom-auth-callback",
100
97
  },
@@ -132,8 +129,10 @@ export function WalletScreen() {
132
129
 
133
130
  const handleSignSolanaMessage = async () => {
134
131
  try {
135
- const signature = await solana.signMessage("Hello from Solana!");
136
- Alert.alert("Solana Signed!", `Signature: ${signature.signature.slice(0, 10)}...`);
132
+ if (solana.isAvailable) {
133
+ const signature = await solana.solana.signMessage("Hello from Solana!");
134
+ Alert.alert("Solana Signed!", `Signature: ${signature.signature.slice(0, 10)}...`);
135
+ }
137
136
  } catch (error) {
138
137
  Alert.alert("Error", `Failed to sign: ${error.message}`);
139
138
  }
@@ -141,9 +140,11 @@ export function WalletScreen() {
141
140
 
142
141
  const handleSignEthereumMessage = async () => {
143
142
  try {
144
- const accounts = await ethereum.getAccounts();
145
- const signature = await ethereum.signPersonalMessage("Hello from Ethereum!", accounts[0]);
146
- Alert.alert("Ethereum Signed!", `Signature: ${signature.signature.slice(0, 10)}...`);
143
+ if (ethereum.isAvailable) {
144
+ const accounts = await ethereum.ethereum.getAccounts();
145
+ const signature = await ethereum.ethereum.signPersonalMessage("Hello from Ethereum!", accounts[0]);
146
+ Alert.alert("Ethereum Signed!", `Signature: ${signature.slice(0, 10)}...`);
147
+ }
147
148
  } catch (error) {
148
149
  Alert.alert("Error", `Failed to sign: ${error.message}`);
149
150
  }
@@ -198,15 +199,17 @@ The main provider component that initializes the SDK and provides context to all
198
199
  ```typescript
199
200
  interface PhantomSDKConfig {
200
201
  scheme: string; // Custom URL scheme for your app
201
- embeddedWalletType: "user-wallet" | "app-wallet";
202
+ appId: string; // Your app ID from phantom.com/portal (required)
202
203
  addressTypes: [AddressType, ...AddressType[]]; // e.g., [AddressType.solana]
203
- apiBaseUrl: string; // e.g., "https://api.phantom.app/v1/wallets"
204
- solanaProvider: "web3js" | "kit"; // Solana provider to use
204
+
205
+ // Optional configuration
206
+ embeddedWalletType?: "user-wallet"; // optional, defaults to "user-wallet", currently the only supported type
207
+ apiBaseUrl?: string; // e.g., "https://api.phantom.app/v1/wallets" (optional, has default)
205
208
  authOptions?: {
206
209
  authUrl?: string; // Custom auth URL (optional)
207
210
  redirectUrl?: string; // Custom redirect URL (optional)
208
211
  };
209
- autoConnect?: boolean; // Auto-connect to existing session on SDK instantiation (default: true)
212
+ autoConnect?: boolean; // Auto-connect to existing session on SDK instantiation (optional, defaults to true)
210
213
  }
211
214
  ```
212
215
 
@@ -242,13 +245,18 @@ const {
242
245
  Provides access to Solana-specific operations.
243
246
 
244
247
  ```typescript
245
- const solana = useSolana();
248
+ const { solana, isAvailable } = useSolana();
246
249
 
247
- // Sign a message
248
- const signature = await solana.signMessage("Hello Solana!");
250
+ if (isAvailable) {
251
+ // Sign a message
252
+ const signature = await solana.signMessage("Hello Solana!");
249
253
 
250
- // Sign and send a transaction
251
- const result = await solana.signAndSendTransaction(transaction);
254
+ // Sign a transaction (without sending)
255
+ const signedTx = await solana.signTransaction(transaction);
256
+
257
+ // Sign and send a transaction
258
+ const result = await solana.signAndSendTransaction(transaction);
259
+ }
252
260
  ```
253
261
 
254
262
  #### useEthereum
@@ -256,19 +264,24 @@ const result = await solana.signAndSendTransaction(transaction);
256
264
  Provides access to Ethereum-specific operations.
257
265
 
258
266
  ```typescript
259
- const ethereum = useEthereum();
267
+ const { ethereum, isAvailable } = useEthereum();
268
+
269
+ if (isAvailable) {
270
+ // Get accounts
271
+ const accounts = await ethereum.getAccounts();
260
272
 
261
- // Get accounts
262
- const accounts = await ethereum.getAccounts();
273
+ // Sign a personal message
274
+ const signature = await ethereum.signPersonalMessage("Hello Ethereum!", accounts[0]);
263
275
 
264
- // Sign a personal message
265
- const signature = await ethereum.signPersonalMessage("Hello Ethereum!", accounts[0]);
276
+ // Sign a transaction (without sending)
277
+ const signedTx = await ethereum.signTransaction(transactionData);
266
278
 
267
- // Send a transaction
268
- const result = await ethereum.sendTransaction(transactionData);
279
+ // Sign and send a transaction
280
+ const result = await ethereum.sendTransaction(transactionData);
269
281
 
270
- // Get current chain ID
271
- const chainId = await ethereum.getChainId();
282
+ // Get current chain ID
283
+ const chainId = await ethereum.getChainId();
284
+ }
272
285
  ```
273
286
 
274
287
  #### useDisconnect
@@ -330,11 +343,9 @@ import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
330
343
 
331
344
  <PhantomProvider
332
345
  config={{
333
- appId: "app_123456789",
346
+ appId: "your-app-id",
334
347
  scheme: "myapp",
335
- embeddedWalletType: "user-wallet",
336
348
  addressTypes: [AddressType.solana],
337
- apiBaseUrl: "https://api.phantom.app/v1/wallets",
338
349
  }}
339
350
  >
340
351
  <App />
@@ -348,14 +359,10 @@ import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
348
359
 
349
360
  <PhantomProvider
350
361
  config={{
351
- appId: "app_123456789",
362
+ appId: "your-app-id",
352
363
  scheme: "mycompany-wallet",
353
- embeddedWalletType: "user-wallet",
354
364
  addressTypes: [AddressType.solana, AddressType.ethereum],
355
- apiBaseUrl: "https://api.phantom.app/v1/wallets",
356
- solanaProvider: "web3js",
357
365
  authOptions: {
358
- authUrl: "https://connect.phantom.app",
359
366
  redirectUrl: "mycompany-wallet://auth/success",
360
367
  },
361
368
  }}
@@ -389,13 +396,9 @@ import { PhantomProvider, AddressType } from '@phantom/react-native-sdk';
389
396
  const testConfig = {
390
397
  appId: "test-app",
391
398
  scheme: "testapp",
392
- embeddedWalletType: "app-wallet" as const,
393
399
  addressTypes: [AddressType.solana],
394
- apiBaseUrl: "https://api.phantom.app/v1/wallets",
395
-
396
400
  };
397
401
 
398
- // Use app-wallet for testing (no OAuth required)
399
402
  <PhantomProvider config={testConfig}>
400
403
  <TestApp />
401
404
  </PhantomProvider>
@@ -420,7 +423,7 @@ adb shell am start -W -a android.intent.action.VIEW -d "myapp://phantom-auth-cal
420
423
  - Check `app.json` (Expo) or platform-specific configuration
421
424
 
422
425
  2. **"Authentication failed"**
423
- - Verify your organization ID is correct
426
+ - Verify your app ID is correct
424
427
  - Check network connectivity
425
428
  - Ensure redirect URL matches your scheme
426
429
 
@@ -444,6 +447,7 @@ import { PhantomProvider, type PhantomSDKConfig, type PhantomDebugConfig } from
444
447
  function App() {
445
448
  // SDK configuration - static, won't change when debug settings change
446
449
  const config: PhantomSDKConfig = {
450
+ appId: "your-app-id",
447
451
  scheme: "mywalletapp",
448
452
  // ... other config
449
453
  };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { ReactNode } from 'react';
3
3
  import * as _phantom_embedded_provider_core from '@phantom/embedded-provider-core';
4
4
  import { EmbeddedProviderConfig, EmbeddedProvider, WalletAddress, ConnectResult } from '@phantom/embedded-provider-core';
5
5
  export { ConnectResult, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
6
- import { ISolanaChain, IEthereumChain, EthTransactionRequest } from '@phantom/chains';
6
+ import * as _phantom_chain_interfaces from '@phantom/chain-interfaces';
7
7
  export { AddressType } from '@phantom/client';
8
8
  export { NetworkId } from '@phantom/constants';
9
9
 
@@ -11,11 +11,19 @@ interface PhantomDebugConfig {
11
11
  /** Enable debug logging */
12
12
  enabled?: boolean;
13
13
  }
14
- interface PhantomSDKConfig extends EmbeddedProviderConfig {
14
+ interface PhantomSDKConfig extends Omit<EmbeddedProviderConfig, "apiBaseUrl" | "embeddedWalletType" | "authOptions"> {
15
15
  /** Custom URL scheme for your app (e.g., "myapp") */
16
16
  scheme: string;
17
17
  /** Enable auto-connect to existing sessions (default: true) */
18
18
  autoConnect?: boolean;
19
+ /** Base URL for Phantom API (default: "https://api.phantom.app/v1/wallets") */
20
+ apiBaseUrl?: string;
21
+ /** Authentication options */
22
+ embeddedWalletType?: "app-wallet" | "user-wallet";
23
+ authOptions?: {
24
+ authUrl?: string;
25
+ redirectUrl?: string;
26
+ };
19
27
  }
20
28
  interface ConnectOptions {
21
29
  /** OAuth provider to use */
@@ -27,7 +35,7 @@ interface ConnectOptions {
27
35
  }
28
36
 
29
37
  interface PhantomContextValue {
30
- sdk: EmbeddedProvider | null;
38
+ sdk: EmbeddedProvider;
31
39
  isConnected: boolean;
32
40
  isConnecting: boolean;
33
41
  connectError: Error | null;
@@ -64,50 +72,21 @@ declare function useAccounts(): {
64
72
  /**
65
73
  * Hook for Solana chain operations in React Native
66
74
  *
67
- * @returns Solana chain interface and convenient methods
75
+ * @returns Solana chain interface with connection enforcement
68
76
  */
69
77
  declare function useSolana(): {
70
- solana: ISolanaChain | null;
71
- signMessage: (message: string | Uint8Array) => Promise<{
72
- signature: Uint8Array;
73
- publicKey: string;
74
- }>;
75
- signTransaction: <T>(transaction: T) => Promise<T>;
76
- signAndSendTransaction: <T>(transaction: T) => Promise<{
77
- signature: string;
78
- }>;
79
- connect: (options?: {
80
- onlyIfTrusted?: boolean;
81
- }) => Promise<{
82
- publicKey: string;
83
- }>;
84
- disconnect: () => Promise<void>;
85
- switchNetwork: (network: "mainnet" | "devnet") => Promise<void | undefined>;
86
- getPublicKey: () => Promise<string | null>;
78
+ solana: _phantom_chain_interfaces.ISolanaChain;
87
79
  isAvailable: boolean;
88
- isConnected: boolean;
89
80
  };
90
81
 
91
82
  /**
92
83
  * Hook for Ethereum chain operations in React Native
93
84
  *
94
- * @returns Ethereum chain interface and convenient methods
85
+ * @returns Ethereum chain interface with connection enforcement
95
86
  */
96
87
  declare function useEthereum(): {
97
- ethereum: IEthereumChain | null;
98
- request: <T = any>(args: {
99
- method: string;
100
- params?: unknown[];
101
- }) => Promise<T>;
102
- signPersonalMessage: (message: string, address: string) => Promise<string>;
103
- signMessage: (message: string) => Promise<string>;
104
- signTypedData: (typedData: any) => Promise<string>;
105
- sendTransaction: (transaction: EthTransactionRequest) => Promise<string>;
106
- switchChain: (chainId: number) => Promise<void>;
107
- getChainId: () => Promise<number>;
108
- getAccounts: () => Promise<string[]>;
88
+ ethereum: _phantom_chain_interfaces.IEthereumChain;
109
89
  isAvailable: boolean;
110
- isConnected: boolean;
111
90
  };
112
91
 
113
92
  export { ConnectOptions, PhantomDebugConfig, PhantomProvider, PhantomSDKConfig, useAccounts, useConnect, useDisconnect, useEthereum, usePhantom, useSolana };
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  AddressType: () => import_client.AddressType,
34
- NetworkId: () => import_constants.NetworkId,
34
+ NetworkId: () => import_constants3.NetworkId,
35
35
  PhantomProvider: () => PhantomProvider,
36
36
  useAccounts: () => useAccounts,
37
37
  useConnect: () => useConnect,
@@ -45,6 +45,7 @@ module.exports = __toCommonJS(src_exports);
45
45
  // src/PhantomProvider.tsx
46
46
  var import_react = require("react");
47
47
  var import_embedded_provider_core = require("@phantom/embedded-provider-core");
48
+ var import_constants2 = require("@phantom/constants");
48
49
 
49
50
  // src/providers/embedded/storage.ts
50
51
  var SecureStore = __toESM(require("expo-secure-store"));
@@ -96,14 +97,14 @@ var ExpoSecureStorage = class {
96
97
 
97
98
  // src/providers/embedded/auth.ts
98
99
  var WebBrowser = __toESM(require("expo-web-browser"));
99
- var DEFAULT_AUTH_URL = "https://auth.phantom.app";
100
+ var import_constants = require("@phantom/constants");
100
101
  var ExpoAuthProvider = class {
101
102
  async authenticate(options) {
102
103
  if ("jwtToken" in options) {
103
104
  return;
104
105
  }
105
106
  const phantomOptions = options;
106
- const { authUrl, redirectUrl, organizationId, parentOrganizationId, sessionId, provider, customAuthData, appId } = phantomOptions;
107
+ const { authUrl, redirectUrl, organizationId, sessionId, provider, customAuthData, appId } = phantomOptions;
107
108
  if (!redirectUrl) {
108
109
  throw new Error("redirectUrl is required for web browser authentication");
109
110
  }
@@ -111,14 +112,14 @@ var ExpoAuthProvider = class {
111
112
  throw new Error("organizationId, sessionId and appId are required for authentication");
112
113
  }
113
114
  try {
114
- const baseUrl = authUrl || DEFAULT_AUTH_URL;
115
+ const baseUrl = authUrl || import_constants.DEFAULT_AUTH_URL;
115
116
  const params = new URLSearchParams({
116
117
  organization_id: organizationId,
117
- parent_organization_id: parentOrganizationId,
118
118
  app_id: appId,
119
119
  redirect_uri: redirectUrl,
120
120
  session_id: sessionId,
121
- clear_previous_session: "true"
121
+ clear_previous_session: "true",
122
+ sdk_version: "1.0.0-beta.10"
122
123
  });
123
124
  if (provider) {
124
125
  console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
@@ -136,7 +137,6 @@ var ExpoAuthProvider = class {
136
137
  baseUrl,
137
138
  redirectUrl,
138
139
  organizationId,
139
- parentOrganizationId,
140
140
  sessionId,
141
141
  provider,
142
142
  hasCustomData: !!customAuthData
@@ -262,7 +262,7 @@ var ReactNativeStamper = class {
262
262
  this.algorithm = import_sdk_types.Algorithm.ed25519;
263
263
  this.type = "PKI";
264
264
  this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
265
- this.organizationId = config.organizationId || "default";
265
+ this.appId = config.appId || "default";
266
266
  }
267
267
  /**
268
268
  * Initialize the stamper and generate/load cryptographic keys
@@ -415,10 +415,10 @@ var ReactNativeStamper = class {
415
415
  return null;
416
416
  }
417
417
  getActiveKeyName() {
418
- return `${this.keyPrefix}-${this.organizationId}-active`;
418
+ return `${this.keyPrefix}-${this.appId}-active`;
419
419
  }
420
420
  getPendingKeyName() {
421
- return `${this.keyPrefix}-${this.organizationId}-pending`;
421
+ return `${this.keyPrefix}-${this.appId}-pending`;
422
422
  }
423
423
  };
424
424
 
@@ -459,34 +459,48 @@ function PhantomProvider({ children, config, debugConfig }) {
459
459
  const [connectError, setConnectError] = (0, import_react.useState)(null);
460
460
  const [addresses, setAddresses] = (0, import_react.useState)([]);
461
461
  const [walletId, setWalletId] = (0, import_react.useState)(null);
462
- const [sdk, setSdk] = (0, import_react.useState)(null);
463
462
  const memoizedConfig = (0, import_react.useMemo)(() => {
464
463
  const redirectUrl = config.authOptions?.redirectUrl || `${config.scheme}://phantom-auth-callback`;
465
464
  return {
466
465
  ...config,
466
+ apiBaseUrl: config.apiBaseUrl || import_constants2.DEFAULT_WALLET_API_URL,
467
+ embeddedWalletType: config.embeddedWalletType || import_constants2.DEFAULT_EMBEDDED_WALLET_TYPE,
467
468
  authOptions: {
468
469
  ...config.authOptions || {},
469
- redirectUrl
470
+ redirectUrl,
471
+ authUrl: config.authOptions?.authUrl || import_constants2.DEFAULT_AUTH_URL
470
472
  }
471
473
  };
472
474
  }, [config]);
473
- (0, import_react.useEffect)(() => {
475
+ const sdk = (0, import_react.useMemo)(() => {
474
476
  const storage = new ExpoSecureStorage();
475
477
  const authProvider = new ExpoAuthProvider();
476
478
  const urlParamsAccessor = new ExpoURLParamsAccessor();
477
479
  const logger = new ExpoLogger(debugConfig?.enabled || false);
478
480
  const stamper = new ReactNativeStamper({
479
- keyPrefix: `phantom-rn-${memoizedConfig.organizationId}`,
480
- organizationId: memoizedConfig.organizationId
481
+ keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
482
+ appId: memoizedConfig.appId
481
483
  });
484
+ const platformName = `${import_react_native2.Platform.OS}-${import_react_native2.Platform.Version}`;
482
485
  const platform = {
483
486
  storage,
484
487
  authProvider,
485
488
  urlParamsAccessor,
486
489
  stamper,
487
- name: `${import_react_native2.Platform.OS}-${import_react_native2.Platform.Version}`
490
+ name: platformName,
491
+ analyticsHeaders: {
492
+ [import_constants2.ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
493
+ [import_constants2.ANALYTICS_HEADERS.PLATFORM]: import_react_native2.Platform.OS,
494
+ [import_constants2.ANALYTICS_HEADERS.PLATFORM_VERSION]: `${import_react_native2.Platform.Version}`,
495
+ [import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
496
+ [import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
497
+ [import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.10"
498
+ // Replaced at build time
499
+ }
488
500
  };
489
- const sdkInstance = new import_embedded_provider_core.EmbeddedProvider(memoizedConfig, platform, logger);
501
+ return new import_embedded_provider_core.EmbeddedProvider(memoizedConfig, platform, logger);
502
+ }, [memoizedConfig, debugConfig, config.appId, config.embeddedWalletType]);
503
+ (0, import_react.useEffect)(() => {
490
504
  const handleConnectStart = () => {
491
505
  setIsConnecting(true);
492
506
  setConnectError(null);
@@ -495,12 +509,12 @@ function PhantomProvider({ children, config, debugConfig }) {
495
509
  try {
496
510
  setIsConnected(true);
497
511
  setIsConnecting(false);
498
- const addrs = await sdkInstance.getAddresses();
512
+ const addrs = await sdk.getAddresses();
499
513
  setAddresses(addrs);
500
514
  } catch (err) {
501
515
  console.error("Error connecting:", err);
502
516
  try {
503
- await sdkInstance.disconnect();
517
+ await sdk.disconnect();
504
518
  } catch (err2) {
505
519
  console.error("Error disconnecting:", err2);
506
520
  }
@@ -517,21 +531,18 @@ function PhantomProvider({ children, config, debugConfig }) {
517
531
  setAddresses([]);
518
532
  setWalletId(null);
519
533
  };
520
- sdkInstance.on("connect_start", handleConnectStart);
521
- sdkInstance.on("connect", handleConnect);
522
- sdkInstance.on("connect_error", handleConnectError);
523
- sdkInstance.on("disconnect", handleDisconnect);
524
- setSdk(sdkInstance);
534
+ sdk.on("connect_start", handleConnectStart);
535
+ sdk.on("connect", handleConnect);
536
+ sdk.on("connect_error", handleConnectError);
537
+ sdk.on("disconnect", handleDisconnect);
525
538
  return () => {
526
- sdkInstance.off("connect_start", handleConnectStart);
527
- sdkInstance.off("connect", handleConnect);
528
- sdkInstance.off("connect_error", handleConnectError);
529
- sdkInstance.off("disconnect", handleDisconnect);
539
+ sdk.off("connect_start", handleConnectStart);
540
+ sdk.off("connect", handleConnect);
541
+ sdk.off("connect_error", handleConnectError);
542
+ sdk.off("disconnect", handleDisconnect);
530
543
  };
531
- }, [memoizedConfig, debugConfig]);
544
+ }, [sdk]);
532
545
  (0, import_react.useEffect)(() => {
533
- if (!sdk)
534
- return;
535
546
  if (config.autoConnect !== false) {
536
547
  sdk.autoConnect().catch(() => {
537
548
  });
@@ -628,181 +639,30 @@ function useAccounts() {
628
639
  }
629
640
 
630
641
  // src/hooks/useSolana.ts
631
- var import_react4 = require("react");
632
642
  function useSolana() {
633
643
  const { sdk, isConnected } = usePhantom();
634
- const solanaChain = (0, import_react4.useMemo)(() => {
635
- if (!sdk || !isConnected)
636
- return null;
637
- try {
638
- return sdk.solana;
639
- } catch {
640
- return null;
641
- }
642
- }, [sdk, isConnected]);
643
- const signMessage = (0, import_react4.useCallback)(
644
- async (message) => {
645
- if (!solanaChain)
646
- throw new Error("Solana chain not available. Ensure SDK is connected.");
647
- return await solanaChain.signMessage(message);
648
- },
649
- [solanaChain]
650
- );
651
- const signTransaction = (0, import_react4.useCallback)(
652
- async (transaction) => {
653
- if (!solanaChain)
654
- throw new Error("Solana chain not available. Ensure SDK is connected.");
655
- return await solanaChain.signTransaction(transaction);
656
- },
657
- [solanaChain]
658
- );
659
- const signAndSendTransaction = (0, import_react4.useCallback)(
660
- async (transaction) => {
661
- if (!solanaChain)
662
- throw new Error("Solana chain not available. Ensure SDK is connected.");
663
- return await solanaChain.signAndSendTransaction(transaction);
664
- },
665
- [solanaChain]
666
- );
667
- const connect = (0, import_react4.useCallback)(
668
- async (options) => {
669
- if (!solanaChain)
670
- throw new Error("Solana chain not available. Ensure SDK is connected.");
671
- return await solanaChain.connect(options);
672
- },
673
- [solanaChain]
674
- );
675
- const disconnect = (0, import_react4.useCallback)(async () => {
676
- if (!solanaChain)
677
- throw new Error("Solana chain not available. Ensure SDK is connected.");
678
- return await solanaChain.disconnect();
679
- }, [solanaChain]);
680
- const switchNetwork = (0, import_react4.useCallback)(
681
- async (network) => {
682
- if (!solanaChain)
683
- throw new Error("Solana chain not available. Ensure SDK is connected.");
684
- return await solanaChain.switchNetwork?.(network);
685
- },
686
- [solanaChain]
687
- );
688
- const getPublicKey = (0, import_react4.useCallback)(async () => {
689
- if (!solanaChain)
690
- return null;
691
- return await solanaChain.getPublicKey();
692
- }, [solanaChain]);
693
644
  return {
694
- // Chain instance for advanced usage
695
- solana: solanaChain,
696
- // Convenient methods
697
- signMessage,
698
- signTransaction,
699
- signAndSendTransaction,
700
- connect,
701
- disconnect,
702
- switchNetwork,
703
- getPublicKey,
645
+ // Chain instance with connection enforcement for signing methods
646
+ solana: sdk.solana,
704
647
  // State
705
- isAvailable: !!solanaChain,
706
- isConnected: solanaChain?.isConnected() ?? false
648
+ isAvailable: !!isConnected
707
649
  };
708
650
  }
709
651
 
710
652
  // src/hooks/useEthereum.ts
711
- var import_react5 = require("react");
712
653
  function useEthereum() {
713
654
  const { sdk, isConnected } = usePhantom();
714
- const ethereumChain = (0, import_react5.useMemo)(() => {
715
- if (!sdk || !isConnected)
716
- return null;
717
- try {
718
- return sdk.ethereum;
719
- } catch {
720
- return null;
721
- }
722
- }, [sdk, isConnected]);
723
- const request = (0, import_react5.useCallback)(
724
- async (args) => {
725
- if (!ethereumChain)
726
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
727
- return await ethereumChain.request(args);
728
- },
729
- [ethereumChain]
730
- );
731
- const signPersonalMessage = (0, import_react5.useCallback)(
732
- async (message, address) => {
733
- if (!ethereumChain)
734
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
735
- return await ethereumChain.signPersonalMessage(message, address);
736
- },
737
- [ethereumChain]
738
- );
739
- const sendTransaction = (0, import_react5.useCallback)(
740
- async (transaction) => {
741
- if (!ethereumChain)
742
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
743
- return await ethereumChain.sendTransaction(transaction);
744
- },
745
- [ethereumChain]
746
- );
747
- const switchChain = (0, import_react5.useCallback)(
748
- async (chainId) => {
749
- if (!ethereumChain)
750
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
751
- return await ethereumChain.switchChain(chainId);
752
- },
753
- [ethereumChain]
754
- );
755
- const getChainId = (0, import_react5.useCallback)(async () => {
756
- if (!ethereumChain)
757
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
758
- return await ethereumChain.getChainId();
759
- }, [ethereumChain]);
760
- const getAccounts = (0, import_react5.useCallback)(async () => {
761
- if (!ethereumChain)
762
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
763
- return await ethereumChain.getAccounts();
764
- }, [ethereumChain]);
765
- const signMessage = (0, import_react5.useCallback)(
766
- async (message) => {
767
- const accounts = await getAccounts();
768
- return await request({
769
- method: "eth_sign",
770
- params: [accounts[0], message]
771
- });
772
- },
773
- [request, getAccounts]
774
- );
775
- const signTypedData = (0, import_react5.useCallback)(
776
- async (typedData) => {
777
- if (!ethereumChain)
778
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
779
- const accounts = await getAccounts();
780
- return await ethereumChain.signTypedData(typedData, accounts[0]);
781
- },
782
- [ethereumChain, getAccounts]
783
- );
784
655
  return {
785
- // Chain instance for advanced usage
786
- ethereum: ethereumChain,
787
- // Standard EIP-1193 interface
788
- request,
789
- // Convenient methods
790
- signPersonalMessage,
791
- signMessage,
792
- signTypedData,
793
- sendTransaction,
794
- switchChain,
795
- getChainId,
796
- getAccounts,
656
+ // Chain instance with connection enforcement for signing methods
657
+ ethereum: sdk.ethereum,
797
658
  // State
798
- isAvailable: !!ethereumChain,
799
- isConnected: ethereumChain?.isConnected() ?? false
659
+ isAvailable: !!isConnected
800
660
  };
801
661
  }
802
662
 
803
663
  // src/index.ts
804
664
  var import_client = require("@phantom/client");
805
- var import_constants = require("@phantom/constants");
665
+ var import_constants3 = require("@phantom/constants");
806
666
  // Annotate the CommonJS export names for ESM import in node:
807
667
  0 && (module.exports = {
808
668
  AddressType,
package/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  // src/PhantomProvider.tsx
2
2
  import { createContext, useContext, useState, useEffect, useMemo } from "react";
3
3
  import { EmbeddedProvider } from "@phantom/embedded-provider-core";
4
+ import { ANALYTICS_HEADERS, DEFAULT_WALLET_API_URL, DEFAULT_EMBEDDED_WALLET_TYPE, DEFAULT_AUTH_URL as DEFAULT_AUTH_URL2 } from "@phantom/constants";
4
5
 
5
6
  // src/providers/embedded/storage.ts
6
7
  import * as SecureStore from "expo-secure-store";
@@ -52,14 +53,14 @@ var ExpoSecureStorage = class {
52
53
 
53
54
  // src/providers/embedded/auth.ts
54
55
  import * as WebBrowser from "expo-web-browser";
55
- var DEFAULT_AUTH_URL = "https://auth.phantom.app";
56
+ import { DEFAULT_AUTH_URL } from "@phantom/constants";
56
57
  var ExpoAuthProvider = class {
57
58
  async authenticate(options) {
58
59
  if ("jwtToken" in options) {
59
60
  return;
60
61
  }
61
62
  const phantomOptions = options;
62
- const { authUrl, redirectUrl, organizationId, parentOrganizationId, sessionId, provider, customAuthData, appId } = phantomOptions;
63
+ const { authUrl, redirectUrl, organizationId, sessionId, provider, customAuthData, appId } = phantomOptions;
63
64
  if (!redirectUrl) {
64
65
  throw new Error("redirectUrl is required for web browser authentication");
65
66
  }
@@ -70,11 +71,11 @@ var ExpoAuthProvider = class {
70
71
  const baseUrl = authUrl || DEFAULT_AUTH_URL;
71
72
  const params = new URLSearchParams({
72
73
  organization_id: organizationId,
73
- parent_organization_id: parentOrganizationId,
74
74
  app_id: appId,
75
75
  redirect_uri: redirectUrl,
76
76
  session_id: sessionId,
77
- clear_previous_session: "true"
77
+ clear_previous_session: "true",
78
+ sdk_version: "1.0.0-beta.10"
78
79
  });
79
80
  if (provider) {
80
81
  console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
@@ -92,7 +93,6 @@ var ExpoAuthProvider = class {
92
93
  baseUrl,
93
94
  redirectUrl,
94
95
  organizationId,
95
- parentOrganizationId,
96
96
  sessionId,
97
97
  provider,
98
98
  hasCustomData: !!customAuthData
@@ -218,7 +218,7 @@ var ReactNativeStamper = class {
218
218
  this.algorithm = Algorithm.ed25519;
219
219
  this.type = "PKI";
220
220
  this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
221
- this.organizationId = config.organizationId || "default";
221
+ this.appId = config.appId || "default";
222
222
  }
223
223
  /**
224
224
  * Initialize the stamper and generate/load cryptographic keys
@@ -371,10 +371,10 @@ var ReactNativeStamper = class {
371
371
  return null;
372
372
  }
373
373
  getActiveKeyName() {
374
- return `${this.keyPrefix}-${this.organizationId}-active`;
374
+ return `${this.keyPrefix}-${this.appId}-active`;
375
375
  }
376
376
  getPendingKeyName() {
377
- return `${this.keyPrefix}-${this.organizationId}-pending`;
377
+ return `${this.keyPrefix}-${this.appId}-pending`;
378
378
  }
379
379
  };
380
380
 
@@ -415,34 +415,48 @@ function PhantomProvider({ children, config, debugConfig }) {
415
415
  const [connectError, setConnectError] = useState(null);
416
416
  const [addresses, setAddresses] = useState([]);
417
417
  const [walletId, setWalletId] = useState(null);
418
- const [sdk, setSdk] = useState(null);
419
418
  const memoizedConfig = useMemo(() => {
420
419
  const redirectUrl = config.authOptions?.redirectUrl || `${config.scheme}://phantom-auth-callback`;
421
420
  return {
422
421
  ...config,
422
+ apiBaseUrl: config.apiBaseUrl || DEFAULT_WALLET_API_URL,
423
+ embeddedWalletType: config.embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE,
423
424
  authOptions: {
424
425
  ...config.authOptions || {},
425
- redirectUrl
426
+ redirectUrl,
427
+ authUrl: config.authOptions?.authUrl || DEFAULT_AUTH_URL2
426
428
  }
427
429
  };
428
430
  }, [config]);
429
- useEffect(() => {
431
+ const sdk = useMemo(() => {
430
432
  const storage = new ExpoSecureStorage();
431
433
  const authProvider = new ExpoAuthProvider();
432
434
  const urlParamsAccessor = new ExpoURLParamsAccessor();
433
435
  const logger = new ExpoLogger(debugConfig?.enabled || false);
434
436
  const stamper = new ReactNativeStamper({
435
- keyPrefix: `phantom-rn-${memoizedConfig.organizationId}`,
436
- organizationId: memoizedConfig.organizationId
437
+ keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
438
+ appId: memoizedConfig.appId
437
439
  });
440
+ const platformName = `${Platform.OS}-${Platform.Version}`;
438
441
  const platform = {
439
442
  storage,
440
443
  authProvider,
441
444
  urlParamsAccessor,
442
445
  stamper,
443
- name: `${Platform.OS}-${Platform.Version}`
446
+ name: platformName,
447
+ analyticsHeaders: {
448
+ [ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
449
+ [ANALYTICS_HEADERS.PLATFORM]: Platform.OS,
450
+ [ANALYTICS_HEADERS.PLATFORM_VERSION]: `${Platform.Version}`,
451
+ [ANALYTICS_HEADERS.APP_ID]: config.appId,
452
+ [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
453
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.10"
454
+ // Replaced at build time
455
+ }
444
456
  };
445
- const sdkInstance = new EmbeddedProvider(memoizedConfig, platform, logger);
457
+ return new EmbeddedProvider(memoizedConfig, platform, logger);
458
+ }, [memoizedConfig, debugConfig, config.appId, config.embeddedWalletType]);
459
+ useEffect(() => {
446
460
  const handleConnectStart = () => {
447
461
  setIsConnecting(true);
448
462
  setConnectError(null);
@@ -451,12 +465,12 @@ function PhantomProvider({ children, config, debugConfig }) {
451
465
  try {
452
466
  setIsConnected(true);
453
467
  setIsConnecting(false);
454
- const addrs = await sdkInstance.getAddresses();
468
+ const addrs = await sdk.getAddresses();
455
469
  setAddresses(addrs);
456
470
  } catch (err) {
457
471
  console.error("Error connecting:", err);
458
472
  try {
459
- await sdkInstance.disconnect();
473
+ await sdk.disconnect();
460
474
  } catch (err2) {
461
475
  console.error("Error disconnecting:", err2);
462
476
  }
@@ -473,21 +487,18 @@ function PhantomProvider({ children, config, debugConfig }) {
473
487
  setAddresses([]);
474
488
  setWalletId(null);
475
489
  };
476
- sdkInstance.on("connect_start", handleConnectStart);
477
- sdkInstance.on("connect", handleConnect);
478
- sdkInstance.on("connect_error", handleConnectError);
479
- sdkInstance.on("disconnect", handleDisconnect);
480
- setSdk(sdkInstance);
490
+ sdk.on("connect_start", handleConnectStart);
491
+ sdk.on("connect", handleConnect);
492
+ sdk.on("connect_error", handleConnectError);
493
+ sdk.on("disconnect", handleDisconnect);
481
494
  return () => {
482
- sdkInstance.off("connect_start", handleConnectStart);
483
- sdkInstance.off("connect", handleConnect);
484
- sdkInstance.off("connect_error", handleConnectError);
485
- sdkInstance.off("disconnect", handleDisconnect);
495
+ sdk.off("connect_start", handleConnectStart);
496
+ sdk.off("connect", handleConnect);
497
+ sdk.off("connect_error", handleConnectError);
498
+ sdk.off("disconnect", handleDisconnect);
486
499
  };
487
- }, [memoizedConfig, debugConfig]);
500
+ }, [sdk]);
488
501
  useEffect(() => {
489
- if (!sdk)
490
- return;
491
502
  if (config.autoConnect !== false) {
492
503
  sdk.autoConnect().catch(() => {
493
504
  });
@@ -584,175 +595,24 @@ function useAccounts() {
584
595
  }
585
596
 
586
597
  // src/hooks/useSolana.ts
587
- import { useCallback as useCallback3, useMemo as useMemo2 } from "react";
588
598
  function useSolana() {
589
599
  const { sdk, isConnected } = usePhantom();
590
- const solanaChain = useMemo2(() => {
591
- if (!sdk || !isConnected)
592
- return null;
593
- try {
594
- return sdk.solana;
595
- } catch {
596
- return null;
597
- }
598
- }, [sdk, isConnected]);
599
- const signMessage = useCallback3(
600
- async (message) => {
601
- if (!solanaChain)
602
- throw new Error("Solana chain not available. Ensure SDK is connected.");
603
- return await solanaChain.signMessage(message);
604
- },
605
- [solanaChain]
606
- );
607
- const signTransaction = useCallback3(
608
- async (transaction) => {
609
- if (!solanaChain)
610
- throw new Error("Solana chain not available. Ensure SDK is connected.");
611
- return await solanaChain.signTransaction(transaction);
612
- },
613
- [solanaChain]
614
- );
615
- const signAndSendTransaction = useCallback3(
616
- async (transaction) => {
617
- if (!solanaChain)
618
- throw new Error("Solana chain not available. Ensure SDK is connected.");
619
- return await solanaChain.signAndSendTransaction(transaction);
620
- },
621
- [solanaChain]
622
- );
623
- const connect = useCallback3(
624
- async (options) => {
625
- if (!solanaChain)
626
- throw new Error("Solana chain not available. Ensure SDK is connected.");
627
- return await solanaChain.connect(options);
628
- },
629
- [solanaChain]
630
- );
631
- const disconnect = useCallback3(async () => {
632
- if (!solanaChain)
633
- throw new Error("Solana chain not available. Ensure SDK is connected.");
634
- return await solanaChain.disconnect();
635
- }, [solanaChain]);
636
- const switchNetwork = useCallback3(
637
- async (network) => {
638
- if (!solanaChain)
639
- throw new Error("Solana chain not available. Ensure SDK is connected.");
640
- return await solanaChain.switchNetwork?.(network);
641
- },
642
- [solanaChain]
643
- );
644
- const getPublicKey = useCallback3(async () => {
645
- if (!solanaChain)
646
- return null;
647
- return await solanaChain.getPublicKey();
648
- }, [solanaChain]);
649
600
  return {
650
- // Chain instance for advanced usage
651
- solana: solanaChain,
652
- // Convenient methods
653
- signMessage,
654
- signTransaction,
655
- signAndSendTransaction,
656
- connect,
657
- disconnect,
658
- switchNetwork,
659
- getPublicKey,
601
+ // Chain instance with connection enforcement for signing methods
602
+ solana: sdk.solana,
660
603
  // State
661
- isAvailable: !!solanaChain,
662
- isConnected: solanaChain?.isConnected() ?? false
604
+ isAvailable: !!isConnected
663
605
  };
664
606
  }
665
607
 
666
608
  // src/hooks/useEthereum.ts
667
- import { useCallback as useCallback4, useMemo as useMemo3 } from "react";
668
609
  function useEthereum() {
669
610
  const { sdk, isConnected } = usePhantom();
670
- const ethereumChain = useMemo3(() => {
671
- if (!sdk || !isConnected)
672
- return null;
673
- try {
674
- return sdk.ethereum;
675
- } catch {
676
- return null;
677
- }
678
- }, [sdk, isConnected]);
679
- const request = useCallback4(
680
- async (args) => {
681
- if (!ethereumChain)
682
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
683
- return await ethereumChain.request(args);
684
- },
685
- [ethereumChain]
686
- );
687
- const signPersonalMessage = useCallback4(
688
- async (message, address) => {
689
- if (!ethereumChain)
690
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
691
- return await ethereumChain.signPersonalMessage(message, address);
692
- },
693
- [ethereumChain]
694
- );
695
- const sendTransaction = useCallback4(
696
- async (transaction) => {
697
- if (!ethereumChain)
698
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
699
- return await ethereumChain.sendTransaction(transaction);
700
- },
701
- [ethereumChain]
702
- );
703
- const switchChain = useCallback4(
704
- async (chainId) => {
705
- if (!ethereumChain)
706
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
707
- return await ethereumChain.switchChain(chainId);
708
- },
709
- [ethereumChain]
710
- );
711
- const getChainId = useCallback4(async () => {
712
- if (!ethereumChain)
713
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
714
- return await ethereumChain.getChainId();
715
- }, [ethereumChain]);
716
- const getAccounts = useCallback4(async () => {
717
- if (!ethereumChain)
718
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
719
- return await ethereumChain.getAccounts();
720
- }, [ethereumChain]);
721
- const signMessage = useCallback4(
722
- async (message) => {
723
- const accounts = await getAccounts();
724
- return await request({
725
- method: "eth_sign",
726
- params: [accounts[0], message]
727
- });
728
- },
729
- [request, getAccounts]
730
- );
731
- const signTypedData = useCallback4(
732
- async (typedData) => {
733
- if (!ethereumChain)
734
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
735
- const accounts = await getAccounts();
736
- return await ethereumChain.signTypedData(typedData, accounts[0]);
737
- },
738
- [ethereumChain, getAccounts]
739
- );
740
611
  return {
741
- // Chain instance for advanced usage
742
- ethereum: ethereumChain,
743
- // Standard EIP-1193 interface
744
- request,
745
- // Convenient methods
746
- signPersonalMessage,
747
- signMessage,
748
- signTypedData,
749
- sendTransaction,
750
- switchChain,
751
- getChainId,
752
- getAccounts,
612
+ // Chain instance with connection enforcement for signing methods
613
+ ethereum: sdk.ethereum,
753
614
  // State
754
- isAvailable: !!ethereumChain,
755
- isConnected: ethereumChain?.isConnected() ?? false
615
+ isAvailable: !!isConnected
756
616
  };
757
617
  }
758
618
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phantom/react-native-sdk",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.10",
4
4
  "description": "Phantom Wallet SDK for React Native and Expo applications",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -45,14 +45,14 @@
45
45
  "directory": "packages/react-native-sdk"
46
46
  },
47
47
  "dependencies": {
48
- "@phantom/api-key-stamper": "^1.0.0-beta.1",
49
- "@phantom/base64url": "^1.0.0-beta.1",
50
- "@phantom/chains": "^1.0.0-beta.1",
51
- "@phantom/client": "^1.0.0-beta.1",
52
- "@phantom/constants": "^1.0.0-beta.1",
53
- "@phantom/crypto": "^1.0.0-beta.1",
54
- "@phantom/embedded-provider-core": "^1.0.0-beta.1",
55
- "@phantom/sdk-types": "^1.0.0-beta.1",
48
+ "@phantom/api-key-stamper": "^1.0.0-beta.6",
49
+ "@phantom/base64url": "^1.0.0-beta.6",
50
+ "@phantom/chain-interfaces": "^1.0.0-beta.6",
51
+ "@phantom/client": "^1.0.0-beta.10",
52
+ "@phantom/constants": "^1.0.0-beta.6",
53
+ "@phantom/crypto": "^1.0.0-beta.6",
54
+ "@phantom/embedded-provider-core": "^1.0.0-beta.10",
55
+ "@phantom/sdk-types": "^1.0.0-beta.6",
56
56
  "@types/bs58": "^5.0.0",
57
57
  "bs58": "^6.0.0",
58
58
  "buffer": "^6.0.3"