@phantom/react-native-sdk 0.1.8 → 1.0.0-beta.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/README.md CHANGED
@@ -89,7 +89,7 @@ export default function App() {
89
89
  return (
90
90
  <PhantomProvider
91
91
  config={{
92
- organizationId: "your-organization-id",
92
+ appId: "your-app-id",
93
93
  scheme: "mywalletapp", // Must match app.json scheme
94
94
  embeddedWalletType: "user-wallet",
95
95
  addressTypes: [AddressType.solana],
@@ -98,7 +98,6 @@ export default function App() {
98
98
  authOptions: {
99
99
  redirectUrl: "mywalletapp://phantom-auth-callback",
100
100
  },
101
- appName: "My Wallet App", // Optional branding
102
101
  }}
103
102
  >
104
103
  <YourAppContent />
@@ -113,12 +112,13 @@ export default function App() {
113
112
  // WalletScreen.tsx
114
113
  import React from "react";
115
114
  import { View, Button, Text, Alert } from "react-native";
116
- import { useConnect, useAccounts, useSignMessage, useDisconnect } from "@phantom/react-native-sdk";
115
+ import { useConnect, useAccounts, useSolana, useEthereum, useDisconnect } from "@phantom/react-native-sdk";
117
116
 
118
117
  export function WalletScreen() {
119
118
  const { connect, isConnecting, error: connectError } = useConnect();
120
119
  const { addresses, isConnected } = useAccounts();
121
- const { signMessage, isSigning } = useSignMessage();
120
+ const solana = useSolana();
121
+ const ethereum = useEthereum();
122
122
  const { disconnect } = useDisconnect();
123
123
 
124
124
  const handleConnect = async () => {
@@ -130,13 +130,20 @@ export function WalletScreen() {
130
130
  }
131
131
  };
132
132
 
133
- const handleSignMessage = async () => {
133
+ const handleSignSolanaMessage = async () => {
134
134
  try {
135
- const signature = await signMessage({
136
- message: "Hello from my React Native app!",
137
- networkId: "solana:mainnet",
138
- });
139
- Alert.alert("Signed!", `Signature: ${signature.slice(0, 10)}...`);
135
+ const signature = await solana.signMessage("Hello from Solana!");
136
+ Alert.alert("Solana Signed!", `Signature: ${signature.signature.slice(0, 10)}...`);
137
+ } catch (error) {
138
+ Alert.alert("Error", `Failed to sign: ${error.message}`);
139
+ }
140
+ };
141
+
142
+ const handleSignEthereumMessage = async () => {
143
+ 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)}...`);
140
147
  } catch (error) {
141
148
  Alert.alert("Error", `Failed to sign: ${error.message}`);
142
149
  }
@@ -158,14 +165,15 @@ export function WalletScreen() {
158
165
  return (
159
166
  <View style={{ padding: 20 }}>
160
167
  <Text style={{ fontSize: 18, marginBottom: 10 }}>Wallet Connected</Text>
161
- <Text>Address: {addresses[0]?.address}</Text>
168
+ {addresses.map((addr, index) => (
169
+ <Text key={index}>
170
+ {addr.addressType}: {addr.address}
171
+ </Text>
172
+ ))}
162
173
 
163
- <Button
164
- title={isSigning ? "Signing..." : "Sign Message"}
165
- onPress={handleSignMessage}
166
- disabled={isSigning}
167
- style={{ marginTop: 10 }}
168
- />
174
+ <Button title="Sign Solana Message" onPress={handleSignSolanaMessage} style={{ marginTop: 10 }} />
175
+
176
+ <Button title="Sign Ethereum Message" onPress={handleSignEthereumMessage} style={{ marginTop: 10 }} />
169
177
 
170
178
  <Button title="Disconnect" onPress={disconnect} style={{ marginTop: 10 }} />
171
179
  </View>
@@ -189,7 +197,6 @@ The main provider component that initializes the SDK and provides context to all
189
197
 
190
198
  ```typescript
191
199
  interface PhantomSDKConfig {
192
- organizationId: string; // Your Phantom organization ID
193
200
  scheme: string; // Custom URL scheme for your app
194
201
  embeddedWalletType: "user-wallet" | "app-wallet";
195
202
  addressTypes: [AddressType, ...AddressType[]]; // e.g., [AddressType.solana]
@@ -199,8 +206,6 @@ interface PhantomSDKConfig {
199
206
  authUrl?: string; // Custom auth URL (optional)
200
207
  redirectUrl?: string; // Custom redirect URL (optional)
201
208
  };
202
- appName?: string; // Optional app name for branding
203
- appLogo?: string; // Optional app logo URL for branding
204
209
  autoConnect?: boolean; // Auto-connect to existing session on SDK instantiation (default: true)
205
210
  }
206
211
  ```
@@ -232,30 +237,38 @@ const {
232
237
  } = useAccounts();
233
238
  ```
234
239
 
235
- #### useSignMessage
240
+ #### useSolana
236
241
 
237
- Handles message signing operations.
242
+ Provides access to Solana-specific operations.
238
243
 
239
244
  ```typescript
240
- const { signMessage, isSigning, error } = useSignMessage();
245
+ const solana = useSolana();
246
+
247
+ // Sign a message
248
+ const signature = await solana.signMessage("Hello Solana!");
241
249
 
242
- const signature = await signMessage({
243
- message: "Message to sign",
244
- networkId: "solana:mainnet", // or 'ethereum:1'
245
- });
250
+ // Sign and send a transaction
251
+ const result = await solana.signAndSendTransaction(transaction);
246
252
  ```
247
253
 
248
- #### useSignAndSendTransaction
254
+ #### useEthereum
249
255
 
250
- Handles transaction signing and sending.
256
+ Provides access to Ethereum-specific operations.
251
257
 
252
258
  ```typescript
253
- const { signAndSendTransaction, isSigning, error } = useSignAndSendTransaction();
259
+ const ethereum = useEthereum();
260
+
261
+ // Get accounts
262
+ const accounts = await ethereum.getAccounts();
263
+
264
+ // Sign a personal message
265
+ const signature = await ethereum.signPersonalMessage("Hello Ethereum!", accounts[0]);
266
+
267
+ // Send a transaction
268
+ const result = await ethereum.sendTransaction(transactionData);
254
269
 
255
- const result = await signAndSendTransaction({
256
- transaction: "base64-encoded-transaction",
257
- networkId: NetworkId.SOLANA_MAINNET,
258
- });
270
+ // Get current chain ID
271
+ const chainId = await ethereum.getChainId();
259
272
  ```
260
273
 
261
274
  #### useDisconnect
@@ -317,7 +330,7 @@ import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
317
330
 
318
331
  <PhantomProvider
319
332
  config={{
320
- organizationId: "org_123456789",
333
+ appId: "app_123456789",
321
334
  scheme: "myapp",
322
335
  embeddedWalletType: "user-wallet",
323
336
  addressTypes: [AddressType.solana],
@@ -328,20 +341,21 @@ import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
328
341
  </PhantomProvider>;
329
342
  ```
330
343
 
331
- ### Advanced Configuration
344
+ ### Multi-Chain Configuration
332
345
 
333
346
  ```tsx
334
347
  import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
335
348
 
336
349
  <PhantomProvider
337
350
  config={{
338
- organizationId: "org_123456789",
351
+ appId: "app_123456789",
339
352
  scheme: "mycompany-wallet",
340
353
  embeddedWalletType: "user-wallet",
341
354
  addressTypes: [AddressType.solana, AddressType.ethereum],
342
355
  apiBaseUrl: "https://api.phantom.app/v1/wallets",
356
+ solanaProvider: "web3js",
343
357
  authOptions: {
344
- authUrl: "https://auth.yourcompany.com",
358
+ authUrl: "https://connect.phantom.app",
345
359
  redirectUrl: "mycompany-wallet://auth/success",
346
360
  },
347
361
  }}
@@ -373,7 +387,7 @@ import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
373
387
  import { PhantomProvider, AddressType } from '@phantom/react-native-sdk';
374
388
 
375
389
  const testConfig = {
376
- organizationId: "test-org",
390
+ appId: "test-app",
377
391
  scheme: "testapp",
378
392
  embeddedWalletType: "app-wallet" as const,
379
393
  addressTypes: [AddressType.solana],
@@ -430,7 +444,6 @@ import { PhantomProvider, type PhantomSDKConfig, type PhantomDebugConfig } from
430
444
  function App() {
431
445
  // SDK configuration - static, won't change when debug settings change
432
446
  const config: PhantomSDKConfig = {
433
- organizationId: "your-org-id",
434
447
  scheme: "mywalletapp",
435
448
  // ... other config
436
449
  };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
3
  import * as _phantom_embedded_provider_core from '@phantom/embedded-provider-core';
4
- import { EmbeddedProviderConfig, EmbeddedProvider, WalletAddress, ConnectResult, SignMessageParams, SignMessageResult, SignAndSendTransactionParams, SignedTransaction } from '@phantom/embedded-provider-core';
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
7
  export { AddressType } from '@phantom/client';
7
8
  export { NetworkId } from '@phantom/constants';
8
9
 
@@ -40,14 +41,10 @@ interface PhantomProviderProps {
40
41
  debugConfig?: PhantomDebugConfig;
41
42
  }
42
43
  declare function PhantomProvider({ children, config, debugConfig }: PhantomProviderProps): react_jsx_runtime.JSX.Element;
43
- /**
44
- * Hook to access the Phantom context
45
- * Must be used within a PhantomProvider
46
- */
47
44
  declare function usePhantom(): PhantomContextValue;
48
45
 
49
46
  declare function useConnect(): {
50
- connect: (options?: ConnectOptions) => Promise<ConnectResult>;
47
+ connect: (_options?: ConnectOptions) => Promise<ConnectResult>;
51
48
  isConnecting: boolean;
52
49
  error: Error | null;
53
50
  };
@@ -64,16 +61,53 @@ declare function useAccounts(): {
64
61
  walletId: string | null;
65
62
  };
66
63
 
67
- declare function useSignMessage(): {
68
- signMessage: (params: SignMessageParams) => Promise<SignMessageResult>;
69
- isSigning: boolean;
70
- error: Error | null;
64
+ /**
65
+ * Hook for Solana chain operations in React Native
66
+ *
67
+ * @returns Solana chain interface and convenient methods
68
+ */
69
+ 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>;
87
+ isAvailable: boolean;
88
+ isConnected: boolean;
71
89
  };
72
90
 
73
- declare function useSignAndSendTransaction(): {
74
- signAndSendTransaction: (params: SignAndSendTransactionParams) => Promise<SignedTransaction>;
75
- isSigning: boolean;
76
- error: Error | null;
91
+ /**
92
+ * Hook for Ethereum chain operations in React Native
93
+ *
94
+ * @returns Ethereum chain interface and convenient methods
95
+ */
96
+ 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[]>;
109
+ isAvailable: boolean;
110
+ isConnected: boolean;
77
111
  };
78
112
 
79
- export { ConnectOptions, PhantomDebugConfig, PhantomProvider, PhantomSDKConfig, useAccounts, useConnect, useDisconnect, usePhantom, useSignAndSendTransaction, useSignMessage };
113
+ export { ConnectOptions, PhantomDebugConfig, PhantomProvider, PhantomSDKConfig, useAccounts, useConnect, useDisconnect, useEthereum, usePhantom, useSolana };
package/dist/index.js CHANGED
@@ -36,9 +36,9 @@ __export(src_exports, {
36
36
  useAccounts: () => useAccounts,
37
37
  useConnect: () => useConnect,
38
38
  useDisconnect: () => useDisconnect,
39
+ useEthereum: () => useEthereum,
39
40
  usePhantom: () => usePhantom,
40
- useSignAndSendTransaction: () => useSignAndSendTransaction,
41
- useSignMessage: () => useSignMessage
41
+ useSolana: () => useSolana
42
42
  });
43
43
  module.exports = __toCommonJS(src_exports);
44
44
 
@@ -103,35 +103,22 @@ var ExpoAuthProvider = class {
103
103
  return;
104
104
  }
105
105
  const phantomOptions = options;
106
- const {
107
- authUrl,
108
- redirectUrl,
109
- organizationId,
110
- parentOrganizationId,
111
- sessionId,
112
- provider,
113
- customAuthData,
114
- appName,
115
- appLogo
116
- } = phantomOptions;
106
+ const { authUrl, redirectUrl, organizationId, parentOrganizationId, sessionId, provider, customAuthData, appId } = phantomOptions;
117
107
  if (!redirectUrl) {
118
108
  throw new Error("redirectUrl is required for web browser authentication");
119
109
  }
120
- if (!organizationId || !sessionId) {
121
- throw new Error("organizationId and sessionId are required for authentication");
110
+ if (!organizationId || !sessionId || !appId) {
111
+ throw new Error("organizationId, sessionId and appId are required for authentication");
122
112
  }
123
113
  try {
124
114
  const baseUrl = authUrl || DEFAULT_AUTH_URL;
125
115
  const params = new URLSearchParams({
126
116
  organization_id: organizationId,
127
117
  parent_organization_id: parentOrganizationId,
118
+ app_id: appId,
128
119
  redirect_uri: redirectUrl,
129
120
  session_id: sessionId,
130
- clear_previous_session: "true",
131
- app_name: appName || "",
132
- // Optional app name
133
- app_logo: appLogo || ""
134
- // Optional app logo URL
121
+ clear_previous_session: "true"
135
122
  });
136
123
  if (provider) {
137
124
  console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
@@ -261,33 +248,6 @@ var ExpoURLParamsAccessor = class {
261
248
  }
262
249
  };
263
250
 
264
- // src/providers/embedded/logger.ts
265
- var ExpoLogger = class {
266
- constructor(enabled = false) {
267
- this.enabled = enabled;
268
- }
269
- info(category, message, data) {
270
- if (this.enabled) {
271
- console.info(`[${category}] ${message}`, data);
272
- }
273
- }
274
- warn(category, message, data) {
275
- if (this.enabled) {
276
- console.warn(`[${category}] ${message}`, data);
277
- }
278
- }
279
- error(category, message, data) {
280
- if (this.enabled) {
281
- console.error(`[${category}] ${message}`, data);
282
- }
283
- }
284
- log(category, message, data) {
285
- if (this.enabled) {
286
- console.log(`[${category}] ${message}`, data);
287
- }
288
- }
289
- };
290
-
291
251
  // src/providers/embedded/stamper.ts
292
252
  var SecureStore2 = __toESM(require("expo-secure-store"));
293
253
  var import_api_key_stamper = require("@phantom/api-key-stamper");
@@ -462,6 +422,33 @@ var ReactNativeStamper = class {
462
422
  }
463
423
  };
464
424
 
425
+ // src/providers/embedded/logger.ts
426
+ var ExpoLogger = class {
427
+ constructor(enabled = false) {
428
+ this.enabled = enabled;
429
+ }
430
+ info(category, message, data) {
431
+ if (this.enabled) {
432
+ console.info(`[${category}] ${message}`, data);
433
+ }
434
+ }
435
+ warn(category, message, data) {
436
+ if (this.enabled) {
437
+ console.warn(`[${category}] ${message}`, data);
438
+ }
439
+ }
440
+ error(category, message, data) {
441
+ if (this.enabled) {
442
+ console.error(`[${category}] ${message}`, data);
443
+ }
444
+ }
445
+ log(category, message, data) {
446
+ if (this.enabled) {
447
+ console.log(`[${category}] ${message}`, data);
448
+ }
449
+ }
450
+ };
451
+
465
452
  // src/PhantomProvider.tsx
466
453
  var import_react_native2 = require("react-native");
467
454
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -560,21 +547,13 @@ function PhantomProvider({ children, config, debugConfig }) {
560
547
  walletId,
561
548
  setWalletId
562
549
  }),
563
- [
564
- sdk,
565
- isConnected,
566
- isConnecting,
567
- connectError,
568
- addresses,
569
- walletId,
570
- setWalletId
571
- ]
550
+ [sdk, isConnected, isConnecting, connectError, addresses, walletId, setWalletId]
572
551
  );
573
552
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PhantomContext.Provider, { value, children });
574
553
  }
575
554
  function usePhantom() {
576
555
  const context = (0, import_react.useContext)(PhantomContext);
577
- if (!context) {
556
+ if (context === void 0) {
578
557
  throw new Error("usePhantom must be used within a PhantomProvider");
579
558
  }
580
559
  return context;
@@ -585,12 +564,12 @@ var import_react2 = require("react");
585
564
  function useConnect() {
586
565
  const { sdk, isConnecting, connectError, setWalletId } = usePhantom();
587
566
  const connect = (0, import_react2.useCallback)(
588
- async (options) => {
567
+ async (_options) => {
589
568
  if (!sdk) {
590
569
  throw new Error("SDK not initialized");
591
570
  }
592
571
  try {
593
- const result = await sdk.connect(options);
572
+ const result = await sdk.connect();
594
573
  if (result.status === "completed" && result.walletId) {
595
574
  setWalletId(result.walletId);
596
575
  }
@@ -648,69 +627,176 @@ function useAccounts() {
648
627
  };
649
628
  }
650
629
 
651
- // src/hooks/useSignMessage.ts
630
+ // src/hooks/useSolana.ts
652
631
  var import_react4 = require("react");
653
- function useSignMessage() {
654
- const { sdk } = usePhantom();
655
- const [isSigning, setIsSigning] = (0, import_react4.useState)(false);
656
- const [error, setError] = (0, import_react4.useState)(null);
632
+ function useSolana() {
633
+ 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]);
657
643
  const signMessage = (0, import_react4.useCallback)(
658
- async (params) => {
659
- if (!sdk) {
660
- throw new Error("SDK not initialized");
661
- }
662
- setIsSigning(true);
663
- setError(null);
664
- try {
665
- const signature = await sdk.signMessage(params);
666
- return signature;
667
- } catch (err) {
668
- const error2 = err;
669
- setError(error2);
670
- throw error2;
671
- } finally {
672
- setIsSigning(false);
673
- }
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);
674
685
  },
675
- [sdk]
686
+ [solanaChain]
676
687
  );
688
+ const getPublicKey = (0, import_react4.useCallback)(async () => {
689
+ if (!solanaChain)
690
+ return null;
691
+ return await solanaChain.getPublicKey();
692
+ }, [solanaChain]);
677
693
  return {
694
+ // Chain instance for advanced usage
695
+ solana: solanaChain,
696
+ // Convenient methods
678
697
  signMessage,
679
- isSigning,
680
- error
698
+ signTransaction,
699
+ signAndSendTransaction,
700
+ connect,
701
+ disconnect,
702
+ switchNetwork,
703
+ getPublicKey,
704
+ // State
705
+ isAvailable: !!solanaChain,
706
+ isConnected: solanaChain?.isConnected() ?? false
681
707
  };
682
708
  }
683
709
 
684
- // src/hooks/useSignAndSendTransaction.ts
710
+ // src/hooks/useEthereum.ts
685
711
  var import_react5 = require("react");
686
- function useSignAndSendTransaction() {
687
- const { sdk } = usePhantom();
688
- const [isSigning, setIsSigning] = (0, import_react5.useState)(false);
689
- const [error, setError] = (0, import_react5.useState)(null);
690
- const signAndSendTransaction = (0, import_react5.useCallback)(
691
- async (params) => {
692
- if (!sdk) {
693
- throw new Error("SDK not initialized");
694
- }
695
- setIsSigning(true);
696
- setError(null);
697
- try {
698
- const result = await sdk.signAndSendTransaction(params);
699
- return result;
700
- } catch (err) {
701
- const error2 = err;
702
- setError(error2);
703
- throw error2;
704
- } finally {
705
- setIsSigning(false);
706
- }
712
+ function useEthereum() {
713
+ 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);
707
728
  },
708
- [sdk]
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]
709
783
  );
710
784
  return {
711
- signAndSendTransaction,
712
- isSigning,
713
- error
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,
797
+ // State
798
+ isAvailable: !!ethereumChain,
799
+ isConnected: ethereumChain?.isConnected() ?? false
714
800
  };
715
801
  }
716
802
 
@@ -725,7 +811,7 @@ var import_constants = require("@phantom/constants");
725
811
  useAccounts,
726
812
  useConnect,
727
813
  useDisconnect,
814
+ useEthereum,
728
815
  usePhantom,
729
- useSignAndSendTransaction,
730
- useSignMessage
816
+ useSolana
731
817
  });
package/dist/index.mjs CHANGED
@@ -59,35 +59,22 @@ var ExpoAuthProvider = class {
59
59
  return;
60
60
  }
61
61
  const phantomOptions = options;
62
- const {
63
- authUrl,
64
- redirectUrl,
65
- organizationId,
66
- parentOrganizationId,
67
- sessionId,
68
- provider,
69
- customAuthData,
70
- appName,
71
- appLogo
72
- } = phantomOptions;
62
+ const { authUrl, redirectUrl, organizationId, parentOrganizationId, sessionId, provider, customAuthData, appId } = phantomOptions;
73
63
  if (!redirectUrl) {
74
64
  throw new Error("redirectUrl is required for web browser authentication");
75
65
  }
76
- if (!organizationId || !sessionId) {
77
- throw new Error("organizationId and sessionId are required for authentication");
66
+ if (!organizationId || !sessionId || !appId) {
67
+ throw new Error("organizationId, sessionId and appId are required for authentication");
78
68
  }
79
69
  try {
80
70
  const baseUrl = authUrl || DEFAULT_AUTH_URL;
81
71
  const params = new URLSearchParams({
82
72
  organization_id: organizationId,
83
73
  parent_organization_id: parentOrganizationId,
74
+ app_id: appId,
84
75
  redirect_uri: redirectUrl,
85
76
  session_id: sessionId,
86
- clear_previous_session: "true",
87
- app_name: appName || "",
88
- // Optional app name
89
- app_logo: appLogo || ""
90
- // Optional app logo URL
77
+ clear_previous_session: "true"
91
78
  });
92
79
  if (provider) {
93
80
  console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
@@ -217,33 +204,6 @@ var ExpoURLParamsAccessor = class {
217
204
  }
218
205
  };
219
206
 
220
- // src/providers/embedded/logger.ts
221
- var ExpoLogger = class {
222
- constructor(enabled = false) {
223
- this.enabled = enabled;
224
- }
225
- info(category, message, data) {
226
- if (this.enabled) {
227
- console.info(`[${category}] ${message}`, data);
228
- }
229
- }
230
- warn(category, message, data) {
231
- if (this.enabled) {
232
- console.warn(`[${category}] ${message}`, data);
233
- }
234
- }
235
- error(category, message, data) {
236
- if (this.enabled) {
237
- console.error(`[${category}] ${message}`, data);
238
- }
239
- }
240
- log(category, message, data) {
241
- if (this.enabled) {
242
- console.log(`[${category}] ${message}`, data);
243
- }
244
- }
245
- };
246
-
247
207
  // src/providers/embedded/stamper.ts
248
208
  import * as SecureStore2 from "expo-secure-store";
249
209
  import { ApiKeyStamper } from "@phantom/api-key-stamper";
@@ -418,6 +378,33 @@ var ReactNativeStamper = class {
418
378
  }
419
379
  };
420
380
 
381
+ // src/providers/embedded/logger.ts
382
+ var ExpoLogger = class {
383
+ constructor(enabled = false) {
384
+ this.enabled = enabled;
385
+ }
386
+ info(category, message, data) {
387
+ if (this.enabled) {
388
+ console.info(`[${category}] ${message}`, data);
389
+ }
390
+ }
391
+ warn(category, message, data) {
392
+ if (this.enabled) {
393
+ console.warn(`[${category}] ${message}`, data);
394
+ }
395
+ }
396
+ error(category, message, data) {
397
+ if (this.enabled) {
398
+ console.error(`[${category}] ${message}`, data);
399
+ }
400
+ }
401
+ log(category, message, data) {
402
+ if (this.enabled) {
403
+ console.log(`[${category}] ${message}`, data);
404
+ }
405
+ }
406
+ };
407
+
421
408
  // src/PhantomProvider.tsx
422
409
  import { Platform } from "react-native";
423
410
  import { jsx } from "react/jsx-runtime";
@@ -516,21 +503,13 @@ function PhantomProvider({ children, config, debugConfig }) {
516
503
  walletId,
517
504
  setWalletId
518
505
  }),
519
- [
520
- sdk,
521
- isConnected,
522
- isConnecting,
523
- connectError,
524
- addresses,
525
- walletId,
526
- setWalletId
527
- ]
506
+ [sdk, isConnected, isConnecting, connectError, addresses, walletId, setWalletId]
528
507
  );
529
508
  return /* @__PURE__ */ jsx(PhantomContext.Provider, { value, children });
530
509
  }
531
510
  function usePhantom() {
532
511
  const context = useContext(PhantomContext);
533
- if (!context) {
512
+ if (context === void 0) {
534
513
  throw new Error("usePhantom must be used within a PhantomProvider");
535
514
  }
536
515
  return context;
@@ -541,12 +520,12 @@ import { useCallback } from "react";
541
520
  function useConnect() {
542
521
  const { sdk, isConnecting, connectError, setWalletId } = usePhantom();
543
522
  const connect = useCallback(
544
- async (options) => {
523
+ async (_options) => {
545
524
  if (!sdk) {
546
525
  throw new Error("SDK not initialized");
547
526
  }
548
527
  try {
549
- const result = await sdk.connect(options);
528
+ const result = await sdk.connect();
550
529
  if (result.status === "completed" && result.walletId) {
551
530
  setWalletId(result.walletId);
552
531
  }
@@ -604,69 +583,176 @@ function useAccounts() {
604
583
  };
605
584
  }
606
585
 
607
- // src/hooks/useSignMessage.ts
608
- import { useState as useState3, useCallback as useCallback3 } from "react";
609
- function useSignMessage() {
610
- const { sdk } = usePhantom();
611
- const [isSigning, setIsSigning] = useState3(false);
612
- const [error, setError] = useState3(null);
586
+ // src/hooks/useSolana.ts
587
+ import { useCallback as useCallback3, useMemo as useMemo2 } from "react";
588
+ function useSolana() {
589
+ 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]);
613
599
  const signMessage = useCallback3(
614
- async (params) => {
615
- if (!sdk) {
616
- throw new Error("SDK not initialized");
617
- }
618
- setIsSigning(true);
619
- setError(null);
620
- try {
621
- const signature = await sdk.signMessage(params);
622
- return signature;
623
- } catch (err) {
624
- const error2 = err;
625
- setError(error2);
626
- throw error2;
627
- } finally {
628
- setIsSigning(false);
629
- }
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);
630
641
  },
631
- [sdk]
642
+ [solanaChain]
632
643
  );
644
+ const getPublicKey = useCallback3(async () => {
645
+ if (!solanaChain)
646
+ return null;
647
+ return await solanaChain.getPublicKey();
648
+ }, [solanaChain]);
633
649
  return {
650
+ // Chain instance for advanced usage
651
+ solana: solanaChain,
652
+ // Convenient methods
634
653
  signMessage,
635
- isSigning,
636
- error
654
+ signTransaction,
655
+ signAndSendTransaction,
656
+ connect,
657
+ disconnect,
658
+ switchNetwork,
659
+ getPublicKey,
660
+ // State
661
+ isAvailable: !!solanaChain,
662
+ isConnected: solanaChain?.isConnected() ?? false
637
663
  };
638
664
  }
639
665
 
640
- // src/hooks/useSignAndSendTransaction.ts
641
- import { useState as useState4, useCallback as useCallback4 } from "react";
642
- function useSignAndSendTransaction() {
643
- const { sdk } = usePhantom();
644
- const [isSigning, setIsSigning] = useState4(false);
645
- const [error, setError] = useState4(null);
646
- const signAndSendTransaction = useCallback4(
647
- async (params) => {
648
- if (!sdk) {
649
- throw new Error("SDK not initialized");
650
- }
651
- setIsSigning(true);
652
- setError(null);
653
- try {
654
- const result = await sdk.signAndSendTransaction(params);
655
- return result;
656
- } catch (err) {
657
- const error2 = err;
658
- setError(error2);
659
- throw error2;
660
- } finally {
661
- setIsSigning(false);
662
- }
666
+ // src/hooks/useEthereum.ts
667
+ import { useCallback as useCallback4, useMemo as useMemo3 } from "react";
668
+ function useEthereum() {
669
+ 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);
663
684
  },
664
- [sdk]
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]
665
739
  );
666
740
  return {
667
- signAndSendTransaction,
668
- isSigning,
669
- error
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,
753
+ // State
754
+ isAvailable: !!ethereumChain,
755
+ isConnected: ethereumChain?.isConnected() ?? false
670
756
  };
671
757
  }
672
758
 
@@ -680,7 +766,7 @@ export {
680
766
  useAccounts,
681
767
  useConnect,
682
768
  useDisconnect,
769
+ useEthereum,
683
770
  usePhantom,
684
- useSignAndSendTransaction,
685
- useSignMessage
771
+ useSolana
686
772
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phantom/react-native-sdk",
3
- "version": "0.1.8",
3
+ "version": "1.0.0-beta.1",
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,13 +45,14 @@
45
45
  "directory": "packages/react-native-sdk"
46
46
  },
47
47
  "dependencies": {
48
- "@phantom/api-key-stamper": "^0.1.5",
49
- "@phantom/base64url": "^0.1.0",
50
- "@phantom/client": "^0.1.11",
51
- "@phantom/constants": "^0.0.3",
52
- "@phantom/crypto": "^0.1.2",
53
- "@phantom/embedded-provider-core": "^0.1.10",
54
- "@phantom/sdk-types": "^0.1.5",
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",
55
56
  "@types/bs58": "^5.0.0",
56
57
  "bs58": "^6.0.0",
57
58
  "buffer": "^6.0.3"