@phantom/react-sdk 1.0.0-beta.9 → 1.0.0

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
@@ -41,7 +41,7 @@ function App() {
41
41
  return (
42
42
  <PhantomProvider
43
43
  config={{
44
- providerType: "injected", // Uses Phantom browser extension
44
+ providers: ["injected"], // Only allow Phantom browser extension
45
45
  addressTypes: [AddressType.solana, AddressType.ethereum],
46
46
  }}
47
47
  >
@@ -52,11 +52,11 @@ function App() {
52
52
 
53
53
  function WalletComponent() {
54
54
  const { connect, isConnecting } = useConnect();
55
- const solana = useSolana();
56
- const ethereum = useEthereum();
55
+ const { solana } = useSolana();
56
+ const { ethereum } = useEthereum();
57
57
 
58
58
  const handleConnect = async () => {
59
- const { addresses } = await connect();
59
+ const { addresses } = await connect({ provider: "injected" });
60
60
  console.log("Connected addresses:", addresses);
61
61
  };
62
62
 
@@ -83,7 +83,7 @@ function WalletComponent() {
83
83
  }
84
84
  ```
85
85
 
86
- ### Embedded Wallet Setup
86
+ ### Multiple Authentication Methods
87
87
 
88
88
  ```tsx
89
89
  import { PhantomProvider } from "@phantom/react-sdk";
@@ -93,8 +93,8 @@ function App() {
93
93
  return (
94
94
  <PhantomProvider
95
95
  config={{
96
- providerType: "embedded",
97
- appId: "your-app-id", // Get your app ID from phantom.com/portal
96
+ providers: ["google", "apple", "phantom", "injected"], // Allow all auth methods
97
+ appId: "your-app-id", // Get your app ID from phantom.com/portal (required for embedded providers)
98
98
  addressTypes: [AddressType.solana, AddressType.ethereum],
99
99
  }}
100
100
  >
@@ -104,6 +104,354 @@ function App() {
104
104
  }
105
105
  ```
106
106
 
107
+ ## Connection Modal
108
+
109
+ The SDK includes a built-in connection modal UI that provides a user-friendly interface for connecting to Phantom. The modal supports multiple connection methods (Google, Apple, Phantom Login, browser extension) and handles all connection logic automatically.
110
+
111
+ ### Using the Modal
112
+
113
+ To use the modal, pass a `theme` prop to `PhantomProvider` and use the `useModal()` hook to control visibility:
114
+
115
+ ```tsx
116
+ import { PhantomProvider, useModal, darkTheme, usePhantom } from "@phantom/react-sdk";
117
+ import { AddressType } from "@phantom/browser-sdk";
118
+
119
+ function App() {
120
+ return (
121
+ <PhantomProvider
122
+ config={{
123
+ providers: ["google", "apple", "phantom", "injected"],
124
+ appId: "your-app-id",
125
+ addressTypes: [AddressType.solana, AddressType.ethereum],
126
+ }}
127
+ theme={darkTheme}
128
+ appIcon="https://your-app.com/icon.png"
129
+ appName="Your App Name"
130
+ >
131
+ <WalletComponent />
132
+ </PhantomProvider>
133
+ );
134
+ }
135
+
136
+ function WalletComponent() {
137
+ const { open, close, isOpened } = useModal();
138
+ const { isConnected, user } = usePhantom();
139
+
140
+ if (isConnected) {
141
+ return (
142
+ <div>
143
+ <p>Connected as {user?.email || "Unknown"}</p>
144
+ </div>
145
+ );
146
+ }
147
+
148
+ return <button onClick={open}>Connect Wallet</button>;
149
+ }
150
+ ```
151
+
152
+ **Modal Features:**
153
+
154
+ - **Multiple Auth Providers**: Google, Apple, Phantom Login, browser extension
155
+ - **Automatic Provider Detection**: Shows browser extension option when Phantom is installed
156
+ - **Mobile Support**: Displays deeplink option for Phantom mobile app on mobile devices
157
+ - **Error Handling**: Clear error messages displayed in the modal
158
+ - **Loading States**: Visual feedback during connection attempts
159
+ - **Responsive Design**: Optimized for both mobile and desktop
160
+
161
+ ### useModal Hook
162
+
163
+ Control the connection modal visibility:
164
+
165
+ ```tsx
166
+ import { useModal } from "@phantom/react-sdk";
167
+
168
+ function ConnectButton() {
169
+ const { open, close, isOpened } = useModal();
170
+
171
+ return (
172
+ <div>
173
+ <button onClick={open}>Open Modal</button>
174
+ <button onClick={close}>Close Modal</button>
175
+ <p>Modal is {isOpened ? "open" : "closed"}</p>
176
+ </div>
177
+ );
178
+ }
179
+ ```
180
+
181
+ **Returns:**
182
+
183
+ - `open()` - Function to open the modal
184
+ - `close()` - Function to close the modal
185
+ - `isOpened` - Boolean indicating if modal is currently visible
186
+
187
+ ### ConnectButton Component
188
+
189
+ A ready-to-use button component that handles the complete connection flow. When disconnected, it shows a "Connect Wallet" button that opens the connection modal. When connected, it displays the truncated wallet address and opens the wallet management modal on click.
190
+
191
+ ```tsx
192
+ import { ConnectButton, AddressType } from "@phantom/react-sdk";
193
+
194
+ function Header() {
195
+ return (
196
+ <div>
197
+ {/* Default: Shows first available address */}
198
+ <ConnectButton />
199
+
200
+ {/* Show specific address type */}
201
+ <ConnectButton addressType={AddressType.solana} />
202
+ <ConnectButton addressType={AddressType.ethereum} />
203
+
204
+ {/* Full width button */}
205
+ <ConnectButton fullWidth />
206
+ </div>
207
+ );
208
+ }
209
+ ```
210
+
211
+ **Props:**
212
+
213
+ - `addressType?: AddressType` - Specify which address type to display when connected (e.g., `AddressType.solana`, `AddressType.ethereum`). If not specified, shows the first available address.
214
+ - `fullWidth?: boolean` - Whether the button should take full width of its container. Default: `false`
215
+
216
+ **Features:**
217
+
218
+ - **When disconnected**: Opens connection modal with auth provider options (Google, Apple, Phantom Login, browser extension)
219
+ - **When connected**: Displays truncated address (e.g., "5Gv8r2...k3Hn") and opens wallet management modal on click
220
+ - **Wallet modal**: Shows all connected addresses and provides a disconnect button
221
+ - Uses theme styling for consistent appearance
222
+ - Fully clickable in both states
223
+
224
+ ### ConnectBox Component
225
+
226
+ An inline embedded component that displays the connection UI directly in your page layout (without a modal backdrop). Perfect for auth callback pages or when you want a more integrated connection experience. The component automatically handles all connection states including loading, error, and success during the auth callback flow.
227
+
228
+ ```tsx
229
+ import { ConnectBox } from "@phantom/react-sdk";
230
+
231
+ function AuthCallbackPage() {
232
+ return (
233
+ <div>
234
+ <h1>Connecting to Phantom...</h1>
235
+ <ConnectBox />
236
+ </div>
237
+ );
238
+ }
239
+ ```
240
+
241
+ **Props:**
242
+
243
+ - `maxWidth?: string | number` - Maximum width of the box. Can be a string (e.g., `"500px"`) or number (e.g., `500`). Default: `"350px"`
244
+ - `transparent?: boolean` - When `true`, removes background, border, and shadow for a transparent appearance. Default: `false`
245
+ - `appIcon?: string` - URL to your app icon (optional, can also be set via `PhantomProvider`)
246
+ - `appName?: string` - Your app name (optional, can also be set via `PhantomProvider`)
247
+
248
+ **Usage Examples:**
249
+
250
+ ```tsx
251
+ import { ConnectBox } from "@phantom/react-sdk";
252
+
253
+ // Default usage
254
+ <ConnectBox />
255
+
256
+ // Custom width
257
+ <ConnectBox maxWidth="500px" />
258
+
259
+ // Transparent (no background/border)
260
+ <ConnectBox transparent />
261
+
262
+ // Custom width with transparent
263
+ <ConnectBox maxWidth={600} transparent />
264
+ ```
265
+
266
+ **Features:**
267
+
268
+ - **Inline embedded**: Renders directly in page flow (not as a floating modal)
269
+ - **Auto state management**: Automatically shows connection/login UI when disconnected, wallet info when connected
270
+ - **Auth callback support**: Handles loading and error states during OAuth callback flows
271
+ - **No close button**: Designed for embedded use cases where users shouldn't dismiss the UI
272
+ - **Theme-aware**: Uses your configured theme for consistent styling
273
+ - **Responsive**: Adapts to mobile and desktop layouts
274
+
275
+ **Use Cases:**
276
+
277
+ - Auth callback pages (e.g., `/auth/callback`) where users return from OAuth providers
278
+ - Embedded wallet connection flows in your app's layout
279
+ - Custom connection pages where you want full control over the page design
280
+
281
+ ### Handling Auth Callback Pages
282
+
283
+ When using embedded authentication providers (Google, Apple, Phantom Login, etc.), users are redirected to your app's callback URL after authentication. The SDK automatically handles the callback and completes the connection. Here's how to build a callback page if you're not using `ConnectBox`:
284
+
285
+ **Basic Auth Callback Page:**
286
+
287
+ ```tsx
288
+ import { usePhantom, useConnect, useAccounts } from "@phantom/react-sdk";
289
+ import { useNavigate } from "react-router-dom"; // or your router
290
+
291
+ function AuthCallbackPage() {
292
+ const navigate = useNavigate();
293
+ const { isConnected } = usePhantom();
294
+ const { isConnecting, error: connectError } = useConnect();
295
+ const addresses = useAccounts();
296
+
297
+ const handleGoHome = () => {
298
+ navigate("/");
299
+ };
300
+
301
+ // Loading state - SDK is processing the callback
302
+ if (isConnecting) {
303
+ return (
304
+ <div>
305
+ <h1>Connecting to wallet...</h1>
306
+ <p>Please wait while we complete your authentication.</p>
307
+ </div>
308
+ );
309
+ }
310
+
311
+ // Success state - connection completed
312
+ if (isConnected && addresses && addresses.length > 0) {
313
+ return (
314
+ <div>
315
+ <h1>Authentication Successful</h1>
316
+ <p>You are now connected to your wallet.</p>
317
+ <div>
318
+ <h2>Addresses:</h2>
319
+ {addresses.map((addr, index) => (
320
+ <div key={index}>
321
+ <strong>{addr.addressType}:</strong> {addr.address}
322
+ </div>
323
+ ))}
324
+ </div>
325
+ <button onClick={handleGoHome}>Go to Main App</button>
326
+ </div>
327
+ );
328
+ }
329
+
330
+ // Error state - connection failed
331
+ if (connectError) {
332
+ return (
333
+ <div>
334
+ <h1>Authentication Failed</h1>
335
+ <p>{connectError.message || "An unknown error occurred during authentication."}</p>
336
+ <div>
337
+ <button onClick={handleGoHome}>Go to Main App</button>
338
+ </div>
339
+ </div>
340
+ );
341
+ }
342
+
343
+ // Default state (shouldn't normally reach here)
344
+ return (
345
+ <div>
346
+ <h1>Processing authentication...</h1>
347
+ </div>
348
+ );
349
+ }
350
+ ```
351
+
352
+ **Key Points:**
353
+
354
+ - The SDK's `autoConnect()` automatically processes the callback URL parameters when the page loads
355
+ - Use `useConnect()` to access `isConnecting` and `error` states during the callback flow
356
+ - Use `usePhantom()` to check `isConnected` status
357
+ - Use `useAccounts()` to get connected wallet addresses
358
+ - The connection state will automatically update as the SDK processes the callback
359
+ - You can monitor `connectError` to handle authentication failures
360
+
361
+ **Router Setup:**
362
+
363
+ Make sure your callback route is configured in your router:
364
+
365
+ ```tsx
366
+ import { Routes, Route } from "react-router-dom";
367
+ import { PhantomProvider } from "@phantom/react-sdk";
368
+
369
+ function App() {
370
+ return (
371
+ <PhantomProvider config={config} theme={darkTheme}>
372
+ <Routes>
373
+ <Route path="/auth/callback" element={<AuthCallbackPage />} />
374
+ <Route path="/" element={<MainApp />} />
375
+ </Routes>
376
+ </PhantomProvider>
377
+ );
378
+ }
379
+ ```
380
+
381
+ **Note:** For a simpler implementation, consider using the `ConnectBox` component which handles all these states automatically.
382
+
383
+ ## Theming
384
+
385
+ Customize the modal appearance by passing a theme object to the `PhantomProvider`. The SDK includes two built-in themes: `darkTheme` (default) and `lightTheme`.
386
+
387
+ ### Using Built-in Themes
388
+
389
+ ```tsx
390
+ import { PhantomProvider, darkTheme, lightTheme } from "@phantom/react-sdk";
391
+
392
+ // Use dark theme (default)
393
+ <PhantomProvider config={config} theme={darkTheme}>
394
+ <App />
395
+ </PhantomProvider>
396
+
397
+ // Use light theme
398
+ <PhantomProvider config={config} theme={lightTheme}>
399
+ <App />
400
+ </PhantomProvider>
401
+ ```
402
+
403
+ ### Custom Theme
404
+
405
+ You can pass a partial theme object to customize specific properties:
406
+
407
+ ```tsx
408
+ import { PhantomProvider } from "@phantom/react-sdk";
409
+
410
+ const customTheme = {
411
+ background: "#1a1a1a",
412
+ text: "#ffffff",
413
+ secondary: "#98979C",
414
+ brand: "#ab9ff2",
415
+ error: "#ff4444",
416
+ success: "#00ff00",
417
+ borderRadius: "16px",
418
+ overlay: "rgba(0, 0, 0, 0.8)",
419
+ };
420
+
421
+ <PhantomProvider config={config} theme={customTheme} appIcon="https://your-app.com/icon.png" appName="Your App">
422
+ <App />
423
+ </PhantomProvider>;
424
+ ```
425
+
426
+ ### Theme Properties
427
+
428
+ | Property | Type | Description |
429
+ | -------------- | -------- | --------------------------------------------------------- |
430
+ | `background` | `string` | Background color for modal |
431
+ | `text` | `string` | Primary text color |
432
+ | `secondary` | `string` | Secondary color for text, borders, dividers (must be hex) |
433
+ | `brand` | `string` | Brand/primary action color |
434
+ | `error` | `string` | Error state color |
435
+ | `success` | `string` | Success state color |
436
+ | `borderRadius` | `string` | Border radius for buttons and modal |
437
+ | `overlay` | `string` | Overlay background color (with opacity) |
438
+
439
+ **Note:** The `secondary` color must be a hex color value (e.g., `#98979C`) as it's used to derive auxiliary colors with opacity.
440
+
441
+ ### Accessing Theme in Custom Components
442
+
443
+ If you need to access the current theme in your own components, use the `useTheme()` hook:
444
+
445
+ ```tsx
446
+ import { useTheme } from "@phantom/react-sdk";
447
+
448
+ function CustomComponent() {
449
+ const theme = useTheme();
450
+
451
+ return <div style={{ backgroundColor: theme.background, color: theme.text }}>Themed content</div>;
452
+ }
453
+ ```
454
+
107
455
  ## Connection Flow
108
456
 
109
457
  The React SDK follows a clear connection pattern:
@@ -115,12 +463,12 @@ The React SDK follows a clear connection pattern:
115
463
  ```tsx
116
464
  function WalletExample() {
117
465
  const { connect } = useConnect();
118
- const solana = useSolana();
119
- const ethereum = useEthereum();
466
+ const { solana } = useSolana();
467
+ const { ethereum } = useEthereum();
120
468
 
121
- // 1. Connect first
469
+ // 1. Connect first (provider parameter is required)
122
470
  const handleConnect = async () => {
123
- await connect();
471
+ await connect({ provider: "injected" });
124
472
  };
125
473
 
126
474
  // 2. Then use chain-specific operations
@@ -136,39 +484,94 @@ function WalletExample() {
136
484
 
137
485
  ### Connection Options
138
486
 
139
- For embedded user-wallets, you can specify authentication providers:
487
+ The `connect()` method requires a `provider` parameter and automatically switches between providers based on the authentication method you specify:
140
488
 
141
489
  ```tsx
142
490
  const { connect } = useConnect();
143
491
 
144
- // Default: Show provider selection screen
145
- await connect();
492
+ // Connect with injected provider (Phantom extension)
493
+ // Automatically switches to injected provider if not already using it
494
+ await connect({
495
+ provider: "injected",
496
+ });
497
+
498
+ // Connect with Google authentication (embedded provider)
499
+ // Automatically switches to embedded provider if not already using it
500
+ await connect({
501
+ provider: "google",
502
+ });
503
+
504
+ // Connect with Apple authentication (embedded provider)
505
+ // Automatically switches to embedded provider if not already using it
506
+ await connect({
507
+ provider: "apple",
508
+ });
146
509
 
147
- // Google authentication (skips provider selection)
510
+ // Connect with Phantom authentication (embedded provider)
511
+ // Uses Phantom extension or mobile app for authentication
512
+ // Automatically switches to embedded provider if not already using it
148
513
  await connect({
149
- authOptions: {
150
- provider: "google",
151
- },
514
+ provider: "phantom",
152
515
  });
153
516
 
154
- // Apple authentication (skips provider selection)
517
+ // Connect with JWT authentication (embedded provider)
155
518
  await connect({
156
- authOptions: {
157
- provider: "apple",
158
- },
519
+ provider: "jwt",
520
+ jwtToken: "your-jwt-token",
159
521
  });
160
522
  ```
161
523
 
162
- ## Provider Types
524
+ ## SDK Initialization
525
+
526
+ The SDK provides an `isLoading` state to track when initialization and autoconnect are in progress. This is useful for showing loading states before your app is ready.
527
+
528
+ ```tsx
529
+ import { useConnect, usePhantom } from "@phantom/react-sdk";
530
+
531
+ function App() {
532
+ const { isLoading } = usePhantom();
533
+ const { connect } = useConnect();
534
+
535
+ // Show loading state while SDK initializes
536
+ if (isLoading) {
537
+ return (
538
+ <div>
539
+ <h1>Initializing Phantom SDK...</h1>
540
+ <p>Please wait...</p>
541
+ </div>
542
+ );
543
+ }
544
+
545
+ // SDK is ready
546
+ return (
547
+ <div>
548
+ <h1>Welcome!</h1>
549
+ <button onClick={() => connect({ provider: "injected" })}>Connect Wallet</button>
550
+ </div>
551
+ );
552
+ }
553
+ ```
554
+
555
+ ## Authentication Providers
556
+
557
+ The SDK supports multiple authentication providers that you configure via the `providers` array:
558
+
559
+ ### Available Providers
560
+
561
+ - **`"injected"`** - Phantom browser extension
562
+ - **`"google"`** - Google OAuth
563
+ - **`"apple"`** - Apple ID
564
+ - **`"phantom"`** - Phantom Login
565
+ - **`"deeplink"`** - Deeplink to Phantom mobile app (only renders on mobile devices)
163
566
 
164
- ### Injected Provider
567
+ ### Configuration Examples
165
568
 
166
- Uses the Phantom browser extension installed by the user.
569
+ **Browser Extension Only**
167
570
 
168
571
  ```tsx
169
572
  <PhantomProvider
170
573
  config={{
171
- providerType: "injected",
574
+ providers: ["injected"], // Only allow browser extension
172
575
  addressTypes: [AddressType.solana, AddressType.ethereum],
173
576
  }}
174
577
  >
@@ -176,11 +579,39 @@ Uses the Phantom browser extension installed by the user.
176
579
  </PhantomProvider>
177
580
  ```
178
581
 
179
- ### Embedded Provider
582
+ **Multiple Authentication Methods**
180
583
 
181
- Creates non-custodial wallets embedded in your application.
584
+ ```tsx
585
+ <PhantomProvider
586
+ config={{
587
+ providers: ["google", "apple", "phantom", "injected", "deeplink"], // Allow all methods
588
+ appId: "your-app-id", // Required for embedded providers
589
+ addressTypes: [AddressType.solana, AddressType.ethereum],
590
+ }}
591
+ >
592
+ <YourApp />
593
+ </PhantomProvider>
594
+ ```
595
+
596
+ **Mobile Deeplink Support**
182
597
 
183
- #### User Wallet
598
+ The `"deeplink"` provider enables a button that opens the Phantom mobile app on mobile devices. This button only appears on mobile devices when the Phantom browser extension is not installed. When clicked, it redirects users to the Phantom mobile app to complete authentication.
599
+
600
+ ```tsx
601
+ <PhantomProvider
602
+ config={{
603
+ providers: ["google", "apple", "phantom", "deeplink"], // Include deeplink for mobile support
604
+ appId: "your-app-id", // Required for deeplink
605
+ addressTypes: [AddressType.solana, AddressType.ethereum],
606
+ }}
607
+ >
608
+ <YourApp />
609
+ </PhantomProvider>
610
+ ```
611
+
612
+ ### Embedded Wallet Type
613
+
614
+ When using embedded providers (google, apple, phantom, etc.), you can specify the wallet type using `embeddedWalletType`. The default is `"user-wallet"`:
184
615
 
185
616
  - **Uses Phantom authentication** - user logs in with existing account
186
617
  - **Potentially funded** - brings existing wallet balance
@@ -189,16 +620,16 @@ Creates non-custodial wallets embedded in your application.
189
620
  ```tsx
190
621
  <PhantomProvider
191
622
  config={{
192
- providerType: "embedded",
623
+ providers: ["google", "apple", "phantom"],
193
624
  appId: "your-app-id",
194
625
  addressTypes: [AddressType.solana, AddressType.ethereum],
626
+ embeddedWalletType: "user-wallet", // default, can be omitted
195
627
  }}
196
628
  >
197
629
  <YourApp />
198
630
  </PhantomProvider>
199
631
  ```
200
632
 
201
-
202
633
  ## Available Hooks
203
634
 
204
635
  ### Core Connection Hooks
@@ -211,17 +642,22 @@ Connect to wallet:
211
642
  import { useConnect } from "@phantom/react-sdk";
212
643
 
213
644
  function ConnectButton() {
214
- const { connect, isConnecting, error } = useConnect();
645
+ const { connect, isConnecting, isLoading, error } = useConnect();
215
646
 
216
647
  const handleConnect = async () => {
217
648
  try {
218
- const { walletId, addresses } = await connect();
649
+ const { addresses } = await connect({ provider: "injected" });
219
650
  console.log("Connected addresses:", addresses);
220
651
  } catch (err) {
221
652
  console.error("Failed to connect:", err);
222
653
  }
223
654
  };
224
655
 
656
+ // Wait for SDK to finish initializing before showing connect button
657
+ if (isLoading) {
658
+ return <div>Loading...</div>;
659
+ }
660
+
225
661
  return (
226
662
  <button onClick={handleConnect} disabled={isConnecting}>
227
663
  {isConnecting ? "Connecting..." : "Connect Wallet"}
@@ -305,6 +741,29 @@ function ExtensionStatus() {
305
741
  }
306
742
  ```
307
743
 
744
+ #### useIsPhantomLoginAvailable
745
+
746
+ Check if Phantom Login is available (requires extension installed and `phantom_login` feature support):
747
+
748
+ ```tsx
749
+ import { useIsPhantomLoginAvailable } from "@phantom/react-sdk";
750
+
751
+ function PhantomLoginButton() {
752
+ const { isLoading, isAvailable } = useIsPhantomLoginAvailable();
753
+ const { connect } = useConnect();
754
+
755
+ if (isLoading) {
756
+ return <div>Checking Phantom Login availability...</div>;
757
+ }
758
+
759
+ if (!isAvailable) {
760
+ return null; // Don't show button if Phantom Login is not available
761
+ }
762
+
763
+ return <button onClick={() => connect({ provider: "phantom" })}>Login with Phantom</button>;
764
+ }
765
+ ```
766
+
308
767
  ### Chain-Specific Hooks
309
768
 
310
769
  #### useSolana
@@ -316,7 +775,12 @@ import { useSolana } from "@phantom/react-sdk";
316
775
  import { VersionedTransaction, TransactionMessage, SystemProgram, PublicKey, Connection } from "@solana/web3.js";
317
776
 
318
777
  function SolanaOperations() {
319
- const solana = useSolana();
778
+ const { solana, isAvailable } = useSolana();
779
+
780
+ // Check if Solana is available before using it
781
+ if (!isAvailable) {
782
+ return <div>Solana is not available for the current wallet</div>;
783
+ }
320
784
 
321
785
  const signMessage = async () => {
322
786
  const signature = await solana.signMessage("Hello Solana!");
@@ -371,7 +835,19 @@ function SolanaOperations() {
371
835
  - `switchNetwork(network)` - Switch between mainnet/devnet
372
836
  - `getPublicKey()` - Get current public key
373
837
  - `isConnected` - Connection status
374
- - `isAvailable` - Provider availability
838
+ - `isAvailable` - Provider availability (see note below)
839
+
840
+ **Note on `isAvailable`:**
841
+
842
+ The `isAvailable` property indicates whether the Solana chain is available for the currently connected wallet:
843
+
844
+ - **For embedded wallets** (Google, Apple, Phantom Login, etc.): `isAvailable` will be `true` for all networks configured in your `addressTypes` array, as embedded wallets support all configured networks.
845
+
846
+ - **For Phantom injected wallet**: `isAvailable` will be `true` for all networks configured in your `addressTypes` array, as Phantom supports multiple networks.
847
+
848
+ - **For other injected wallets** (discovered via Wallet Standard or EIP-6963): `isAvailable` depends on which networks the specific wallet supports. For example, if you connect to a wallet that only supports Ethereum, `isAvailable` will be `false` for Solana even if Solana is in your `addressTypes` configuration.
849
+
850
+ Always check `isAvailable` before attempting to use chain-specific methods when working with injected wallets that may not support all networks.
375
851
 
376
852
  #### useEthereum
377
853
 
@@ -381,7 +857,12 @@ Hook for Ethereum chain operations:
381
857
  import { useEthereum } from "@phantom/react-sdk";
382
858
 
383
859
  function EthereumOperations() {
384
- const ethereum = useEthereum();
860
+ const { ethereum, isAvailable } = useEthereum();
861
+
862
+ // Check if Ethereum is available before using it
863
+ if (!isAvailable) {
864
+ return <div>Ethereum is not available for the current wallet</div>;
865
+ }
385
866
 
386
867
  const signPersonalMessage = async () => {
387
868
  const accounts = await ethereum.getAccounts();
@@ -466,11 +947,71 @@ function EthereumOperations() {
466
947
  - `signTypedData(typedData)` - Sign EIP-712 typed data
467
948
  - `signTransaction(transaction)` - Sign transaction without sending
468
949
  - `sendTransaction(transaction)` - Sign and send transaction
469
- - `switchChain(chainId)` - Switch chains
950
+ - `switchChain(chainId)` - Switch chains (accepts chain ID as number or a hex string)
470
951
  - `getChainId()` - Get current chain ID
471
952
  - `getAccounts()` - Get connected accounts
472
953
  - `isConnected` - Connection status
473
- - `isAvailable` - Provider availability
954
+ - `isAvailable` - Provider availability (see note below)
955
+
956
+ **Note on `isAvailable`:**
957
+
958
+ The `isAvailable` property indicates whether the Ethereum chain is available for the currently connected wallet:
959
+
960
+ - **For embedded wallets** (Google, Apple, Phantom Login, etc.): `isAvailable` will be `true` for all networks configured in your `addressTypes` array, as embedded wallets support all configured networks.
961
+
962
+ - **For Phantom injected wallet**: `isAvailable` will be `true` for all networks configured in your `addressTypes` array, as Phantom supports multiple networks.
963
+
964
+ - **For other injected wallets** (discovered via Wallet Standard or EIP-6963): `isAvailable` depends on which networks the specific wallet supports. For example, if you connect to a wallet that only supports Solana, `isAvailable` will be `false` for Ethereum even if Ethereum is in your `addressTypes` configuration.
965
+
966
+ Always check `isAvailable` before attempting to use chain-specific methods when working with injected wallets that may not support all networks.
967
+
968
+ **Supported EVM Networks:**
969
+
970
+ | Network | Chain ID | Usage |
971
+ | ---------------- | ---------- | -------------------------------- |
972
+ | Ethereum Mainnet | `1` | `ethereum.switchChain(1)` |
973
+ | Ethereum Sepolia | `11155111` | `ethereum.switchChain(11155111)` |
974
+ | Polygon Mainnet | `137` | `ethereum.switchChain(137)` |
975
+ | Polygon Amoy | `80002` | `ethereum.switchChain(80002)` |
976
+ | Base Mainnet | `8453` | `ethereum.switchChain(8453)` |
977
+ | Base Sepolia | `84532` | `ethereum.switchChain(84532)` |
978
+ | Arbitrum One | `42161` | `ethereum.switchChain(42161)` |
979
+ | Arbitrum Sepolia | `421614` | `ethereum.switchChain(421614)` |
980
+ | Monad Mainnet | `143` | `ethereum.switchChain(143)` |
981
+ | Monad Testnet | `10143` | `ethereum.switchChain(10143)` |
982
+
983
+ ### Wallet Discovery Hook
984
+
985
+ #### useDiscoveredWallets
986
+
987
+ Hook to get discovered injected wallets with automatic loading and error states. Discovers wallets using Wallet Standard (Solana) and EIP-6963 (Ethereum) standards.
988
+
989
+ ```tsx
990
+ import { useDiscoveredWallets } from "@phantom/react-sdk";
991
+
992
+ function WalletSelector() {
993
+ const { wallets, isLoading, error, refetch } = useDiscoveredWallets();
994
+
995
+ // wallets: InjectedWalletInfo[] - Array of discovered wallets
996
+ // isLoading: boolean - Loading state during discovery
997
+ // error: Error | null - Error state if discovery fails
998
+ // refetch: () => Promise<void> - Function to manually trigger discovery
999
+ }
1000
+ ```
1001
+
1002
+ **Returns:**
1003
+
1004
+ - `wallets: InjectedWalletInfo[]` - Array of discovered wallet information
1005
+ - `isLoading: boolean` - `true` while discovery is in progress
1006
+ - `error: Error | null` - Error object if discovery fails, `null` otherwise
1007
+ - `refetch: () => Promise<void>` - Async function to manually refresh the wallet list
1008
+
1009
+ **Behavior:**
1010
+
1011
+ - Automatically fetches discovered wallets when the SDK becomes available
1012
+ - If no wallets are found in the registry, triggers async `discoverWallets()` to discover them
1013
+ - Wallets are filtered based on the `addressTypes` configured in `PhantomProvider`
1014
+ - Phantom wallet is automatically included if available
474
1015
 
475
1016
  ### Auto-Confirm Hook (Injected Provider Only)
476
1017
 
@@ -614,7 +1155,7 @@ import { VersionedTransaction, TransactionMessage, SystemProgram, PublicKey, Con
614
1155
  import { useSolana } from "@phantom/react-sdk";
615
1156
 
616
1157
  function SolanaExample() {
617
- const solana = useSolana();
1158
+ const { solana } = useSolana();
618
1159
 
619
1160
  const sendTransaction = async () => {
620
1161
  // Get recent blockhash
@@ -662,7 +1203,7 @@ import {
662
1203
  import { useSolana } from "@phantom/react-sdk";
663
1204
 
664
1205
  function SolanaKitExample() {
665
- const solana = useSolana();
1206
+ const { solana } = useSolana();
666
1207
 
667
1208
  const sendTransaction = async () => {
668
1209
  const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
@@ -693,7 +1234,7 @@ import { parseEther, parseGwei, encodeFunctionData } from "viem";
693
1234
  import { useEthereum } from "@phantom/react-sdk";
694
1235
 
695
1236
  function EthereumExample() {
696
- const ethereum = useEthereum();
1237
+ const { ethereum } = useEthereum();
697
1238
 
698
1239
  const sendEth = async () => {
699
1240
  const result = await ethereum.sendTransaction({
@@ -733,36 +1274,45 @@ function EthereumExample() {
733
1274
 
734
1275
  Quick reference of all available hooks:
735
1276
 
736
- | Hook | Purpose | Returns |
737
- | ------------------------- | --------------------------------------- | --------------------------------------------------- |
738
- | `useConnect` | Connect to wallet | `{ connect, isConnecting, error }` |
739
- | `useAccounts` | Get wallet addresses | `WalletAddress[]` or `null` |
740
- | `useIsExtensionInstalled` | Check extension status | `{ isLoading, isInstalled }` |
741
- | `useDisconnect` | Disconnect from wallet | `{ disconnect, isDisconnecting }` |
742
- | `useAutoConfirm` | Auto-confirm management (injected only) | `{ enable, disable, status, supportedChains, ... }` |
743
- | `useSolana` | Solana chain operations | `{ signMessage, signAndSendTransaction, ... }` |
744
- | `useEthereum` | Ethereum chain operations | `{ signPersonalMessage, sendTransaction, ... }` |
745
- | `usePhantom` | Get provider context | `{ isConnected, isReady }` |
1277
+ | Hook | Purpose | Returns |
1278
+ | ---------------------------- | --------------------------------------- | --------------------------------------------------- |
1279
+ | `useConnect` | Connect to wallet | `{ connect, isConnecting, error }` |
1280
+ | `useModal` | Control connection modal | `{ open, close, isOpened }` |
1281
+ | `useAccounts` | Get wallet addresses | `WalletAddress[]` or `null` |
1282
+ | `useIsExtensionInstalled` | Check extension status | `{ isLoading, isInstalled }` |
1283
+ | `useIsPhantomLoginAvailable` | Check Phantom Login availability | `{ isLoading, isAvailable }` |
1284
+ | `useDisconnect` | Disconnect from wallet | `{ disconnect, isDisconnecting }` |
1285
+ | `useAutoConfirm` | Auto-confirm management (injected only) | `{ enable, disable, status, supportedChains, ... }` |
1286
+ | `useDiscoveredWallets` | Get discovered injected wallets | `{ wallets, isLoading, error, refetch }` |
1287
+ | `useSolana` | Solana chain operations | `{ signMessage, signAndSendTransaction, ... }` |
1288
+ | `useEthereum` | Ethereum chain operations | `{ signPersonalMessage, sendTransaction, ... }` |
1289
+ | `useTheme` | Access current theme | `PhantomTheme` |
1290
+ | `usePhantom` | Get provider context | `{ isConnected, isReady }` |
746
1291
 
747
1292
  ## Configuration Reference
748
1293
 
749
1294
  ```typescript
750
1295
  interface PhantomSDKConfig {
751
- providerType: "injected" | "embedded";
1296
+ // List of allowed authentication providers (REQUIRED)
1297
+ providers: AuthProviderType[]; // e.g., ["google", "apple", "phantom", "injected"]
1298
+
752
1299
  addressTypes?: [AddressType, ...AddressType[]]; // Networks to enable (e.g., [AddressType.solana])
753
1300
 
754
- // Required for embedded provider only
755
- appId: string; // Your app ID from phantom.com/portal (required for embedded provider)
756
-
1301
+ // Required when using embedded providers (google, apple, phantom)
1302
+ appId?: string; // Your app ID from phantom.com/portal
1303
+
757
1304
  // Optional configuration
758
1305
  apiBaseUrl?: string; // Phantom API base URL (optional, has default)
759
1306
  authOptions?: {
760
1307
  authUrl?: string; // Custom auth URL (optional, defaults to "https://connect.phantom.app/login")
761
1308
  redirectUrl?: string; // Custom redirect URL after authentication (optional)
762
1309
  };
763
- embeddedWalletType?: "user-wallet"; // Wallet type (optional, defaults to "user-wallet", currently the only supported type)
764
- autoConnect?: boolean; // Auto-connect to existing session on SDK instantiation (optional, defaults to true for embedded, false for injected)
1310
+ embeddedWalletType?: "user-wallet"; // Wallet type (optional, defaults to "user-wallet")
1311
+ autoConnect?: boolean; // Auto-connect to existing session (default: true when embedded providers used)
765
1312
  }
1313
+
1314
+ // Valid provider types
1315
+ type AuthProviderType = "google" | "apple" | "phantom" | "injected";
766
1316
  ```
767
1317
 
768
1318
  ## Debug Configuration
@@ -792,8 +1342,9 @@ function App() {
792
1342
 
793
1343
  // SDK configuration - static, won't change when debug settings change
794
1344
  const config: PhantomSDKConfig = {
795
- providerType: "embedded",
1345
+ providers: ["google", "apple", "phantom"],
796
1346
  appId: "your-app-id",
1347
+ addressTypes: [AddressType.solana, AddressType.ethereum],
797
1348
  // ... other config
798
1349
  };
799
1350