@phantom/react-sdk 1.0.0-beta.0 → 1.0.0-beta.2

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
@@ -97,7 +97,6 @@ function App() {
97
97
  embeddedWalletType: "app-wallet", // or 'user-wallet'
98
98
  addressTypes: [AddressType.solana, AddressType.ethereum],
99
99
  apiBaseUrl: "https://api.phantom.app/v1/wallets",
100
- organizationId: "your-org-id",
101
100
  }}
102
101
  >
103
102
  <YourApp />
@@ -153,7 +152,7 @@ await connect({
153
152
  },
154
153
  });
155
154
 
156
- // Apple authentication (skips provider selection)
155
+ // Apple authentication (skips provider selection)
157
156
  await connect({
158
157
  authOptions: {
159
158
  provider: "apple",
@@ -195,7 +194,6 @@ Creates non-custodial wallets embedded in your application.
195
194
  embeddedWalletType: "app-wallet",
196
195
  addressTypes: [AddressType.solana],
197
196
  apiBaseUrl: "https://api.phantom.app/v1/wallets",
198
- organizationId: "your-org-id",
199
197
  }}
200
198
  >
201
199
  <YourApp />
@@ -215,7 +213,6 @@ Creates non-custodial wallets embedded in your application.
215
213
  embeddedWalletType: "user-wallet",
216
214
  addressTypes: [AddressType.solana, AddressType.ethereum],
217
215
  apiBaseUrl: "https://api.phantom.app/v1/wallets",
218
- organizationId: "your-org-id",
219
216
  }}
220
217
  >
221
218
  <YourApp />
@@ -233,7 +230,6 @@ When using `AddressType.solana`, you can choose between two Solana libraries:
233
230
  addressTypes: [AddressType.solana],
234
231
  solanaProvider: "web3js", // or 'kit'
235
232
  apiBaseUrl: "https://api.phantom.app/v1/wallets",
236
- organizationId: "your-org-id",
237
233
  }}
238
234
  >
239
235
  <YourApp />
@@ -378,7 +374,7 @@ function SolanaOperations() {
378
374
  // Create transaction
379
375
  const connection = new Connection("https://api.mainnet-beta.solana.com");
380
376
  const { blockhash } = await connection.getLatestBlockhash();
381
-
377
+
382
378
  const fromAddress = await solana.getPublicKey();
383
379
  const transferInstruction = SystemProgram.transfer({
384
380
  fromPubkey: new PublicKey(fromAddress),
@@ -400,7 +396,7 @@ function SolanaOperations() {
400
396
  };
401
397
 
402
398
  const switchNetwork = async () => {
403
- await solana.switchNetwork('devnet');
399
+ await solana.switchNetwork("devnet");
404
400
  };
405
401
 
406
402
  return (
@@ -408,13 +404,14 @@ function SolanaOperations() {
408
404
  <button onClick={signMessage}>Sign Message</button>
409
405
  <button onClick={signAndSendTransaction}>Send Transaction</button>
410
406
  <button onClick={switchNetwork}>Switch to Devnet</button>
411
- <p>Connected: {solana.isConnected ? 'Yes' : 'No'}</p>
407
+ <p>Connected: {solana.isConnected ? "Yes" : "No"}</p>
412
408
  </div>
413
409
  );
414
410
  }
415
411
  ```
416
412
 
417
413
  **Available methods:**
414
+
418
415
  - `signMessage(message)` - Sign a message
419
416
  - `signTransaction(transaction)` - Sign without sending
420
417
  - `signAndSendTransaction(transaction)` - Sign and send
@@ -447,32 +444,42 @@ function EthereumOperations() {
447
444
  { name: "name", type: "string" },
448
445
  { name: "version", type: "string" },
449
446
  { name: "chainId", type: "uint256" },
450
- { name: "verifyingContract", type: "address" }
447
+ { name: "verifyingContract", type: "address" },
451
448
  ],
452
449
  Mail: [
453
450
  { name: "from", type: "string" },
454
451
  { name: "to", type: "string" },
455
- { name: "contents", type: "string" }
456
- ]
452
+ { name: "contents", type: "string" },
453
+ ],
457
454
  },
458
455
  primaryType: "Mail",
459
456
  domain: {
460
457
  name: "Ether Mail",
461
458
  version: "1",
462
459
  chainId: 1,
463
- verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
460
+ verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
464
461
  },
465
462
  message: {
466
463
  from: "Alice",
467
464
  to: "Bob",
468
- contents: "Hello!"
469
- }
465
+ contents: "Hello!",
466
+ },
470
467
  };
471
468
 
472
469
  const signature = await ethereum.signTypedData(typedData);
473
470
  console.log("Typed data signature:", signature);
474
471
  };
475
472
 
473
+ const signTransaction = async () => {
474
+ const signedTx = await ethereum.signTransaction({
475
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
476
+ value: "1000000000000000000", // 1 ETH in wei
477
+ gas: "21000",
478
+ });
479
+ console.log("Transaction signed:", signedTx);
480
+ // Transaction is signed but not sent - you can broadcast it later
481
+ };
482
+
476
483
  const sendTransaction = async () => {
477
484
  const result = await ethereum.sendTransaction({
478
485
  to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
@@ -490,19 +497,22 @@ function EthereumOperations() {
490
497
  <div>
491
498
  <button onClick={signPersonalMessage}>Sign Personal Message</button>
492
499
  <button onClick={signTypedData}>Sign Typed Data</button>
493
- <button onClick={sendTransaction}>Send Transaction</button>
500
+ <button onClick={signTransaction}>Sign Transaction</button>
501
+ <button onClick={sendTransaction}>Sign & Send Transaction</button>
494
502
  <button onClick={switchChain}>Switch to Polygon</button>
495
- <p>Connected: {ethereum.isConnected ? 'Yes' : 'No'}</p>
503
+ <p>Connected: {ethereum.isConnected ? "Yes" : "No"}</p>
496
504
  </div>
497
505
  );
498
506
  }
499
507
  ```
500
508
 
501
509
  **Available methods:**
510
+
502
511
  - `request(args)` - EIP-1193 requests
503
512
  - `signPersonalMessage(message, address)` - Sign personal message
504
513
  - `signTypedData(typedData)` - Sign EIP-712 typed data
505
- - `sendTransaction(transaction)` - Send transaction
514
+ - `signTransaction(transaction)` - Sign transaction without sending
515
+ - `sendTransaction(transaction)` - Sign and send transaction
506
516
  - `switchChain(chainId)` - Switch chains
507
517
  - `getChainId()` - Get current chain ID
508
518
  - `getAccounts()` - Get connected accounts
@@ -521,21 +531,13 @@ Hook for managing auto-confirm functionality with the Phantom extension. Auto-co
521
531
  import { useAutoConfirm, NetworkId } from "@phantom/react-sdk";
522
532
 
523
533
  function AutoConfirmControls() {
524
- const {
525
- enable,
526
- disable,
527
- status,
528
- supportedChains,
529
- isLoading,
530
- error,
531
- refetch,
532
- } = useAutoConfirm();
534
+ const { enable, disable, status, supportedChains, isLoading, error, refetch } = useAutoConfirm();
533
535
 
534
536
  const handleEnable = async () => {
535
537
  try {
536
538
  // Enable auto-confirm for specific chains
537
539
  const result = await enable({
538
- chains: [NetworkId.SOLANA_DEVNET, NetworkId.ETHEREUM_MAINNET]
540
+ chains: [NetworkId.SOLANA_DEVNET, NetworkId.ETHEREUM_MAINNET],
539
541
  });
540
542
  console.log("Auto-confirm enabled:", result);
541
543
  } catch (err) {
@@ -563,14 +565,14 @@ function AutoConfirmControls() {
563
565
  return (
564
566
  <div>
565
567
  <h3>Auto-Confirm Settings</h3>
566
-
568
+
567
569
  <div>
568
570
  <strong>Status:</strong> {status?.enabled ? "Enabled" : "Disabled"}
569
571
  {status?.chains && (
570
572
  <div>
571
573
  <strong>Active Chains:</strong>
572
574
  <ul>
573
- {status.chains.map((chain) => (
575
+ {status.chains.map(chain => (
574
576
  <li key={chain}>{chain}</li>
575
577
  ))}
576
578
  </ul>
@@ -582,7 +584,7 @@ function AutoConfirmControls() {
582
584
  <strong>Supported Chains:</strong>
583
585
  {supportedChains?.chains && (
584
586
  <ul>
585
- {supportedChains.chains.map((chain) => (
587
+ {supportedChains.chains.map(chain => (
586
588
  <li key={chain}>{chain}</li>
587
589
  ))}
588
590
  </ul>
@@ -635,7 +637,7 @@ interface AutoConfirmSupportedChainsResult {
635
637
  **Available Methods:**
636
638
 
637
639
  - `enable(params)` - Enable auto-confirm for specific chains
638
- - `disable()` - Disable auto-confirm completely
640
+ - `disable()` - Disable auto-confirm completely
639
641
  - `refetch()` - Refresh status and supported chains from extension
640
642
  - `status` - Current auto-confirm status (enabled/disabled and active chains)
641
643
  - `supportedChains` - List of chains that support auto-confirm
@@ -778,29 +780,27 @@ function EthereumExample() {
778
780
 
779
781
  Quick reference of all available hooks:
780
782
 
781
- | Hook | Purpose | Returns |
782
- | --------------------------- | -------------------------- | ---------------------------------------------- |
783
- | `useConnect` | Connect to wallet | `{ connect, isConnecting, error }` |
784
- | `useAccounts` | Get wallet addresses | `WalletAddress[]` or `null` |
785
- | `useIsExtensionInstalled` | Check extension status | `{ isLoading, isInstalled }` |
786
- | `useDisconnect` | Disconnect from wallet | `{ disconnect, isDisconnecting }` |
787
- | `useAutoConfirm` | Auto-confirm management (injected only) | `{ enable, disable, status, supportedChains, ... }` |
788
- | `useSolana` | Solana chain operations | `{ signMessage, signAndSendTransaction, ... }` |
789
- | `useEthereum` | Ethereum chain operations | `{ signPersonalMessage, sendTransaction, ... }`|
790
- | `usePhantom` | Get provider context | `{ isConnected, isReady }` |
783
+ | Hook | Purpose | Returns |
784
+ | ------------------------- | --------------------------------------- | --------------------------------------------------- |
785
+ | `useConnect` | Connect to wallet | `{ connect, isConnecting, error }` |
786
+ | `useAccounts` | Get wallet addresses | `WalletAddress[]` or `null` |
787
+ | `useIsExtensionInstalled` | Check extension status | `{ isLoading, isInstalled }` |
788
+ | `useDisconnect` | Disconnect from wallet | `{ disconnect, isDisconnecting }` |
789
+ | `useAutoConfirm` | Auto-confirm management (injected only) | `{ enable, disable, status, supportedChains, ... }` |
790
+ | `useSolana` | Solana chain operations | `{ signMessage, signAndSendTransaction, ... }` |
791
+ | `useEthereum` | Ethereum chain operations | `{ signPersonalMessage, sendTransaction, ... }` |
792
+ | `usePhantom` | Get provider context | `{ isConnected, isReady }` |
791
793
 
792
794
  ## Configuration Reference
793
795
 
794
796
  ```typescript
795
797
  interface PhantomSDKConfig {
796
798
  providerType: "injected" | "embedded";
797
- appName?: string; // Optional app name for branding
798
- appLogo?: string; // Optional app logo URL for branding
799
799
  addressTypes?: [AddressType, ...AddressType[]]; // Networks to enable (e.g., [AddressType.solana])
800
800
 
801
801
  // Required for embedded provider only
802
802
  apiBaseUrl?: string; // Phantom API base URL
803
- organizationId?: string; // Your organization ID
803
+ appId: string; // Your app ID
804
804
  authOptions?: {
805
805
  authUrl?: string; // Custom auth URL (optional)
806
806
  redirectUrl?: string; // Custom redirect URL (optional)
@@ -819,8 +819,8 @@ The React SDK supports separate debug configuration that can be changed without
819
819
 
820
820
  ```typescript
821
821
  interface PhantomDebugConfig {
822
- enabled?: boolean; // Enable debug logging
823
- level?: DebugLevel; // Debug level (ERROR, WARN, INFO, DEBUG)
822
+ enabled?: boolean; // Enable debug logging
823
+ level?: DebugLevel; // Debug level (ERROR, WARN, INFO, DEBUG)
824
824
  callback?: DebugCallback; // Custom debug message handler
825
825
  }
826
826
  ```
@@ -839,7 +839,6 @@ function App() {
839
839
  // SDK configuration - static, won't change when debug settings change
840
840
  const config: PhantomSDKConfig = {
841
841
  providerType: "embedded",
842
- organizationId: "your-org-id",
843
842
  // ... other config
844
843
  };
845
844
 
@@ -866,12 +865,12 @@ Debug callbacks receive a `DebugMessage` object:
866
865
 
867
866
  ```typescript
868
867
  interface DebugMessage {
869
- timestamp: number; // Unix timestamp
870
- level: DebugLevel; // Message level
871
- category: string; // Component category
872
- message: string; // Debug message text
873
- data?: any; // Additional debug data (optional)
868
+ timestamp: number; // Unix timestamp
869
+ level: DebugLevel; // Message level
870
+ category: string; // Component category
871
+ message: string; // Debug message text
872
+ data?: any; // Additional debug data (optional)
874
873
  }
875
874
  ```
876
875
 
877
- For more details and examples, see the [@phantom/browser-sdk documentation](../browser-sdk/README.md).
876
+ For more details and examples, see the [@phantom/browser-sdk documentation](../browser-sdk/README.md).
package/dist/index.d.ts CHANGED
@@ -3,7 +3,6 @@ import { ReactNode } from 'react';
3
3
  import { BrowserSDKConfig, DebugConfig, AuthOptions, BrowserSDK, WalletAddress, AutoConfirmEnableParams, AutoConfirmResult, AutoConfirmSupportedChainsResult } from '@phantom/browser-sdk';
4
4
  export { AddressType, AutoConfirmEnableParams, AutoConfirmResult, AutoConfirmSupportedChainsResult, DebugLevel, DebugMessage, NetworkId, SignedTransaction, WalletAddress, debug } from '@phantom/browser-sdk';
5
5
  import * as _phantom_embedded_provider_core from '@phantom/embedded-provider-core';
6
- import * as _phantom_parsers from '@phantom/parsers';
7
6
  import { ISolanaChain, IEthereumChain, EthTransactionRequest } from '@phantom/chains';
8
7
  export { EthTransactionRequest, IEthereumChain, ISolanaChain } from '@phantom/chains';
9
8
 
@@ -50,6 +49,10 @@ declare function useDisconnect(): {
50
49
 
51
50
  declare function useAccounts(): _phantom_embedded_provider_core.WalletAddress[] | null;
52
51
 
52
+ /**
53
+ * React hook to check if Phantom extension is installed
54
+ * Uses waitForPhantomExtension for proper detection with retry logic
55
+ */
53
56
  declare function useIsExtensionInstalled(): {
54
57
  isLoading: boolean;
55
58
  isInstalled: boolean;
@@ -73,16 +76,21 @@ declare function useAutoConfirm(): UseAutoConfirmResult;
73
76
  */
74
77
  declare function useSolana(): {
75
78
  solana: ISolanaChain | null;
76
- signMessage: (message: string | Uint8Array) => Promise<_phantom_parsers.ParsedSignatureResult>;
79
+ signMessage: (message: string | Uint8Array) => Promise<{
80
+ signature: Uint8Array;
81
+ publicKey: string;
82
+ }>;
77
83
  signTransaction: <T>(transaction: T) => Promise<T>;
78
- signAndSendTransaction: <T>(transaction: T) => Promise<_phantom_parsers.ParsedTransactionResult>;
84
+ signAndSendTransaction: <T>(transaction: T) => Promise<{
85
+ signature: string;
86
+ }>;
79
87
  connect: (options?: {
80
88
  onlyIfTrusted?: boolean;
81
89
  }) => Promise<{
82
90
  publicKey: string;
83
91
  }>;
84
92
  disconnect: () => Promise<void>;
85
- switchNetwork: (network: "mainnet" | "devnet") => Promise<void>;
93
+ switchNetwork: (network: "mainnet" | "devnet") => Promise<void | undefined>;
86
94
  getPublicKey: () => Promise<string | null>;
87
95
  isAvailable: boolean;
88
96
  isConnected: boolean;
@@ -101,8 +109,9 @@ declare function useEthereum(): {
101
109
  }) => Promise<T>;
102
110
  signPersonalMessage: (message: string, address: string) => Promise<string>;
103
111
  signMessage: (message: string) => Promise<string>;
112
+ signTransaction: (transaction: EthTransactionRequest) => Promise<string>;
104
113
  signTypedData: (typedData: any) => Promise<string>;
105
- sendTransaction: (transaction: EthTransactionRequest) => Promise<_phantom_parsers.ParsedTransactionResult>;
114
+ sendTransaction: (transaction: EthTransactionRequest) => Promise<string>;
106
115
  switchChain: (chainId: number) => Promise<void>;
107
116
  getChainId: () => Promise<number>;
108
117
  getAccounts: () => Promise<string[]>;
package/dist/index.js CHANGED
@@ -52,14 +52,6 @@ var import_browser_sdk = require("@phantom/browser-sdk");
52
52
  var import_jsx_runtime = require("react/jsx-runtime");
53
53
  var PhantomContext = (0, import_react.createContext)(void 0);
54
54
  function PhantomProvider({ children, config, debugConfig }) {
55
- const [isConnected, setIsConnected] = (0, import_react.useState)(false);
56
- const [isConnecting, setIsConnecting] = (0, import_react.useState)(false);
57
- const [connectError, setConnectError] = (0, import_react.useState)(null);
58
- const [addresses, setAddresses] = (0, import_react.useState)([]);
59
- const [walletId, setWalletId] = (0, import_react.useState)(null);
60
- const [currentProviderType, setCurrentProviderType] = (0, import_react.useState)(config.providerType || null);
61
- const [isPhantomAvailable, setIsPhantomAvailable] = (0, import_react.useState)(false);
62
- const [sdk, setSdk] = (0, import_react.useState)(null);
63
55
  const memoizedConfig = (0, import_react.useMemo)(() => {
64
56
  return {
65
57
  ...config,
@@ -67,6 +59,16 @@ function PhantomProvider({ children, config, debugConfig }) {
67
59
  providerType: config.providerType || "embedded"
68
60
  };
69
61
  }, [config]);
62
+ const [isConnected, setIsConnected] = (0, import_react.useState)(false);
63
+ const [isConnecting, setIsConnecting] = (0, import_react.useState)(false);
64
+ const [connectError, setConnectError] = (0, import_react.useState)(null);
65
+ const [addresses, setAddresses] = (0, import_react.useState)([]);
66
+ const [walletId, setWalletId] = (0, import_react.useState)(null);
67
+ const [currentProviderType, setCurrentProviderType] = (0, import_react.useState)(
68
+ memoizedConfig.providerType || null
69
+ );
70
+ const [isPhantomAvailable, setIsPhantomAvailable] = (0, import_react.useState)(false);
71
+ const [sdk, setSdk] = (0, import_react.useState)(null);
70
72
  (0, import_react.useEffect)(() => {
71
73
  const sdkInstance = new import_browser_sdk.BrowserSDK(memoizedConfig);
72
74
  const handleConnectStart = () => {
@@ -123,21 +125,21 @@ function PhantomProvider({ children, config, debugConfig }) {
123
125
  (0, import_react.useEffect)(() => {
124
126
  if (!sdk)
125
127
  return;
126
- const initialize = () => {
128
+ const initialize = async () => {
127
129
  try {
128
- const available = import_browser_sdk.BrowserSDK.isPhantomInstalled();
130
+ const available = await import_browser_sdk.BrowserSDK.isPhantomInstalled();
129
131
  setIsPhantomAvailable(available);
130
132
  } catch (err) {
131
133
  console.error("Error checking Phantom extension:", err);
132
134
  setIsPhantomAvailable(false);
133
135
  }
134
- if (config.autoConnect !== false) {
136
+ if (memoizedConfig.autoConnect !== false) {
135
137
  sdk.autoConnect().catch(() => {
136
138
  });
137
139
  }
138
140
  };
139
141
  initialize();
140
- }, [sdk, config.autoConnect]);
142
+ }, [sdk, memoizedConfig.autoConnect]);
141
143
  const value = (0, import_react.useMemo)(
142
144
  () => ({
143
145
  sdk,
@@ -149,16 +151,7 @@ function PhantomProvider({ children, config, debugConfig }) {
149
151
  currentProviderType,
150
152
  isPhantomAvailable
151
153
  }),
152
- [
153
- sdk,
154
- isConnected,
155
- isConnecting,
156
- connectError,
157
- addresses,
158
- walletId,
159
- currentProviderType,
160
- isPhantomAvailable
161
- ]
154
+ [sdk, isConnected, isConnecting, connectError, addresses, walletId, currentProviderType, isPhantomAvailable]
162
155
  );
163
156
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PhantomContext.Provider, { value, children });
164
157
  }
@@ -235,36 +228,33 @@ function useAccounts() {
235
228
  // src/hooks/useIsExtensionInstalled.ts
236
229
  var React = __toESM(require("react"));
237
230
  var import_browser_sdk2 = require("@phantom/browser-sdk");
238
- var cachedIsInstalled = null;
239
231
  function useIsExtensionInstalled() {
240
- const { sdk } = usePhantom();
241
- const [isLoading, setIsLoading] = React.useState(cachedIsInstalled === null);
242
- const [isInstalled, setIsInstalled] = React.useState(cachedIsInstalled ?? false);
232
+ const [isLoading, setIsLoading] = React.useState(true);
233
+ const [isInstalled, setIsInstalled] = React.useState(false);
243
234
  React.useEffect(() => {
244
- if (!sdk) {
245
- setIsLoading(false);
246
- return;
247
- }
248
- if (cachedIsInstalled !== null) {
249
- setIsInstalled(cachedIsInstalled);
250
- setIsLoading(false);
251
- return;
252
- }
253
- const checkExtension = () => {
235
+ let isMounted = true;
236
+ const checkExtension = async () => {
254
237
  try {
255
238
  setIsLoading(true);
256
- const result = import_browser_sdk2.BrowserSDK.isPhantomInstalled();
257
- cachedIsInstalled = result;
258
- setIsInstalled(result);
239
+ const result = await (0, import_browser_sdk2.waitForPhantomExtension)(3e3);
240
+ if (isMounted) {
241
+ setIsInstalled(result);
242
+ }
259
243
  } catch (error) {
260
- cachedIsInstalled = false;
261
- setIsInstalled(false);
244
+ if (isMounted) {
245
+ setIsInstalled(false);
246
+ }
262
247
  } finally {
263
- setIsLoading(false);
248
+ if (isMounted) {
249
+ setIsLoading(false);
250
+ }
264
251
  }
265
252
  };
266
253
  checkExtension();
267
- }, [sdk]);
254
+ return () => {
255
+ isMounted = false;
256
+ };
257
+ }, []);
268
258
  return { isLoading, isInstalled };
269
259
  }
270
260
 
@@ -301,53 +291,47 @@ function useAutoConfirm() {
301
291
  },
302
292
  [sdk, isInjected]
303
293
  );
304
- const disable = (0, import_react4.useCallback)(
305
- async () => {
306
- if (!sdk) {
307
- throw new Error("SDK not initialized");
308
- }
309
- if (!isInjected) {
310
- throw new Error("Auto-confirm is only available for injected (extension) providers");
311
- }
312
- try {
313
- setIsLoading(true);
314
- setError(null);
315
- await sdk.disableAutoConfirm();
316
- const newStatus = await sdk.getAutoConfirmStatus();
317
- setStatus(newStatus);
318
- } catch (err) {
319
- const error2 = err instanceof Error ? err : new Error("Unknown error occurred");
320
- setError(error2);
321
- throw error2;
322
- } finally {
323
- setIsLoading(false);
324
- }
325
- },
326
- [sdk, isInjected]
327
- );
328
- const refetch = (0, import_react4.useCallback)(
329
- async () => {
330
- if (!sdk || !isInjected) {
331
- return;
332
- }
333
- try {
334
- setIsLoading(true);
335
- setError(null);
336
- const [statusResult, supportedResult] = await Promise.all([
337
- sdk.getAutoConfirmStatus(),
338
- sdk.getSupportedAutoConfirmChains()
339
- ]);
340
- setStatus(statusResult);
341
- setSupportedChains(supportedResult);
342
- } catch (err) {
343
- const error2 = err instanceof Error ? err : new Error("Failed to fetch auto-confirm data");
344
- setError(error2);
345
- } finally {
346
- setIsLoading(false);
347
- }
348
- },
349
- [sdk, isInjected]
350
- );
294
+ const disable = (0, import_react4.useCallback)(async () => {
295
+ if (!sdk) {
296
+ throw new Error("SDK not initialized");
297
+ }
298
+ if (!isInjected) {
299
+ throw new Error("Auto-confirm is only available for injected (extension) providers");
300
+ }
301
+ try {
302
+ setIsLoading(true);
303
+ setError(null);
304
+ await sdk.disableAutoConfirm();
305
+ const newStatus = await sdk.getAutoConfirmStatus();
306
+ setStatus(newStatus);
307
+ } catch (err) {
308
+ const error2 = err instanceof Error ? err : new Error("Unknown error occurred");
309
+ setError(error2);
310
+ throw error2;
311
+ } finally {
312
+ setIsLoading(false);
313
+ }
314
+ }, [sdk, isInjected]);
315
+ const refetch = (0, import_react4.useCallback)(async () => {
316
+ if (!sdk || !isInjected) {
317
+ return;
318
+ }
319
+ try {
320
+ setIsLoading(true);
321
+ setError(null);
322
+ const [statusResult, supportedResult] = await Promise.all([
323
+ sdk.getAutoConfirmStatus(),
324
+ sdk.getSupportedAutoConfirmChains()
325
+ ]);
326
+ setStatus(statusResult);
327
+ setSupportedChains(supportedResult);
328
+ } catch (err) {
329
+ const error2 = err instanceof Error ? err : new Error("Failed to fetch auto-confirm data");
330
+ setError(error2);
331
+ } finally {
332
+ setIsLoading(false);
333
+ }
334
+ }, [sdk, isInjected]);
351
335
  (0, import_react4.useEffect)(() => {
352
336
  if (sdk && isInjected) {
353
337
  refetch();
@@ -372,6 +356,13 @@ function useAutoConfirm() {
372
356
  var import_react5 = require("react");
373
357
  function useSolana() {
374
358
  const { sdk, isConnected } = usePhantom();
359
+ const getSolanaChain = (0, import_react5.useCallback)(() => {
360
+ if (!sdk)
361
+ throw new Error("Phantom SDK not initialized.");
362
+ if (!sdk.isConnected())
363
+ throw new Error("Phantom SDK not connected. Call connect() first.");
364
+ return sdk.solana;
365
+ }, [sdk]);
375
366
  const solanaChain = (0, import_react5.useMemo)(() => {
376
367
  if (!sdk || !isConnected)
377
368
  return null;
@@ -381,41 +372,50 @@ function useSolana() {
381
372
  return null;
382
373
  }
383
374
  }, [sdk, isConnected]);
384
- const signMessage = (0, import_react5.useCallback)(async (message) => {
385
- if (!solanaChain)
386
- throw new Error("Solana chain not available. Ensure SDK is connected.");
387
- return solanaChain.signMessage(message);
388
- }, [solanaChain]);
389
- const signTransaction = (0, import_react5.useCallback)(async (transaction) => {
390
- if (!solanaChain)
391
- throw new Error("Solana chain not available. Ensure SDK is connected.");
392
- return solanaChain.signTransaction(transaction);
393
- }, [solanaChain]);
394
- const signAndSendTransaction = (0, import_react5.useCallback)(async (transaction) => {
395
- if (!solanaChain)
396
- throw new Error("Solana chain not available. Ensure SDK is connected.");
397
- return solanaChain.signAndSendTransaction(transaction);
398
- }, [solanaChain]);
399
- const connect = (0, import_react5.useCallback)(async (options) => {
400
- if (!solanaChain)
401
- throw new Error("Solana chain not available. Ensure SDK is connected.");
402
- return solanaChain.connect(options);
403
- }, [solanaChain]);
375
+ const signMessage = (0, import_react5.useCallback)(
376
+ async (message) => {
377
+ const chain = getSolanaChain();
378
+ return chain.signMessage(message);
379
+ },
380
+ [getSolanaChain]
381
+ );
382
+ const signTransaction = (0, import_react5.useCallback)(
383
+ async (transaction) => {
384
+ const chain = getSolanaChain();
385
+ return chain.signTransaction(transaction);
386
+ },
387
+ [getSolanaChain]
388
+ );
389
+ const signAndSendTransaction = (0, import_react5.useCallback)(
390
+ async (transaction) => {
391
+ const chain = getSolanaChain();
392
+ return chain.signAndSendTransaction(transaction);
393
+ },
394
+ [getSolanaChain]
395
+ );
396
+ const connect = (0, import_react5.useCallback)(
397
+ async (options) => {
398
+ const chain = getSolanaChain();
399
+ return chain.connect(options);
400
+ },
401
+ [getSolanaChain]
402
+ );
404
403
  const disconnect = (0, import_react5.useCallback)(async () => {
405
- if (!solanaChain)
406
- throw new Error("Solana chain not available. Ensure SDK is connected.");
407
- return solanaChain.disconnect();
408
- }, [solanaChain]);
409
- const switchNetwork = (0, import_react5.useCallback)(async (network) => {
410
- if (!solanaChain)
411
- throw new Error("Solana chain not available. Ensure SDK is connected.");
412
- return solanaChain.switchNetwork(network);
413
- }, [solanaChain]);
404
+ const chain = getSolanaChain();
405
+ return chain.disconnect();
406
+ }, [getSolanaChain]);
407
+ const switchNetwork = (0, import_react5.useCallback)(
408
+ async (network) => {
409
+ const chain = getSolanaChain();
410
+ return chain.switchNetwork?.(network);
411
+ },
412
+ [getSolanaChain]
413
+ );
414
414
  const getPublicKey = (0, import_react5.useCallback)(async () => {
415
- if (!solanaChain)
415
+ if (!sdk || !sdk.isConnected())
416
416
  return null;
417
- return solanaChain.getPublicKey();
418
- }, [solanaChain]);
417
+ return sdk.solana.getPublicKey();
418
+ }, [sdk]);
419
419
  return {
420
420
  // Chain instance for advanced usage
421
421
  solana: solanaChain,
@@ -437,6 +437,13 @@ function useSolana() {
437
437
  var import_react6 = require("react");
438
438
  function useEthereum() {
439
439
  const { sdk, isConnected } = usePhantom();
440
+ const getEthereumChain = (0, import_react6.useCallback)(() => {
441
+ if (!sdk)
442
+ throw new Error("Phantom SDK not initialized.");
443
+ if (!sdk.isConnected())
444
+ throw new Error("Phantom SDK not connected. Call connect() first.");
445
+ return sdk.ethereum;
446
+ }, [sdk]);
440
447
  const ethereumChain = (0, import_react6.useMemo)(() => {
441
448
  if (!sdk || !isConnected)
442
449
  return null;
@@ -446,50 +453,70 @@ function useEthereum() {
446
453
  return null;
447
454
  }
448
455
  }, [sdk, isConnected]);
449
- const request = (0, import_react6.useCallback)(async (args) => {
450
- if (!ethereumChain)
451
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
452
- return ethereumChain.request(args);
453
- }, [ethereumChain]);
454
- const signPersonalMessage = (0, import_react6.useCallback)(async (message, address) => {
455
- return request({
456
- method: "personal_sign",
457
- params: [message, address]
458
- });
459
- }, [request]);
460
- const sendTransaction = (0, import_react6.useCallback)(async (transaction) => {
461
- if (!ethereumChain)
462
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
463
- return ethereumChain.sendTransaction(transaction);
464
- }, [ethereumChain]);
465
- const switchChain = (0, import_react6.useCallback)(async (chainId) => {
466
- if (!ethereumChain)
467
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
468
- return ethereumChain.switchChain(chainId);
469
- }, [ethereumChain]);
456
+ const request = (0, import_react6.useCallback)(
457
+ async (args) => {
458
+ const chain = getEthereumChain();
459
+ return chain.request(args);
460
+ },
461
+ [getEthereumChain]
462
+ );
463
+ const signPersonalMessage = (0, import_react6.useCallback)(
464
+ async (message, address) => {
465
+ return request({
466
+ method: "personal_sign",
467
+ params: [message, address]
468
+ });
469
+ },
470
+ [request]
471
+ );
472
+ const signTransaction = (0, import_react6.useCallback)(
473
+ async (transaction) => {
474
+ const chain = getEthereumChain();
475
+ return chain.signTransaction(transaction);
476
+ },
477
+ [getEthereumChain]
478
+ );
479
+ const sendTransaction = (0, import_react6.useCallback)(
480
+ async (transaction) => {
481
+ const chain = getEthereumChain();
482
+ return chain.sendTransaction(transaction);
483
+ },
484
+ [getEthereumChain]
485
+ );
486
+ const switchChain = (0, import_react6.useCallback)(
487
+ async (chainId) => {
488
+ const chain = getEthereumChain();
489
+ return chain.switchChain(chainId);
490
+ },
491
+ [getEthereumChain]
492
+ );
470
493
  const getChainId = (0, import_react6.useCallback)(async () => {
471
- if (!ethereumChain)
472
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
473
- return ethereumChain.getChainId();
474
- }, [ethereumChain]);
494
+ const chain = getEthereumChain();
495
+ return chain.getChainId();
496
+ }, [getEthereumChain]);
475
497
  const getAccounts = (0, import_react6.useCallback)(async () => {
476
- if (!ethereumChain)
477
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
478
- return ethereumChain.getAccounts();
479
- }, [ethereumChain]);
480
- const signMessage = (0, import_react6.useCallback)(async (message) => {
481
- return request({
482
- method: "eth_sign",
483
- params: [await getAccounts().then((accounts) => accounts[0]), message]
484
- });
485
- }, [request, getAccounts]);
486
- const signTypedData = (0, import_react6.useCallback)(async (typedData) => {
487
- const accounts = await getAccounts();
488
- return request({
489
- method: "eth_signTypedData_v4",
490
- params: [accounts[0], JSON.stringify(typedData)]
491
- });
492
- }, [request, getAccounts]);
498
+ const chain = getEthereumChain();
499
+ return chain.getAccounts();
500
+ }, [getEthereumChain]);
501
+ const signMessage = (0, import_react6.useCallback)(
502
+ async (message) => {
503
+ return request({
504
+ method: "eth_sign",
505
+ params: [await getAccounts().then((accounts) => accounts[0]), message]
506
+ });
507
+ },
508
+ [request, getAccounts]
509
+ );
510
+ const signTypedData = (0, import_react6.useCallback)(
511
+ async (typedData) => {
512
+ const accounts = await getAccounts();
513
+ return request({
514
+ method: "eth_signTypedData_v4",
515
+ params: [accounts[0], JSON.stringify(typedData)]
516
+ });
517
+ },
518
+ [request, getAccounts]
519
+ );
493
520
  return {
494
521
  // Chain instance for advanced usage
495
522
  ethereum: ethereumChain,
@@ -498,6 +525,7 @@ function useEthereum() {
498
525
  // Convenient methods
499
526
  signPersonalMessage,
500
527
  signMessage,
528
+ signTransaction,
501
529
  signTypedData,
502
530
  sendTransaction,
503
531
  switchChain,
package/dist/index.mjs CHANGED
@@ -4,14 +4,6 @@ import { BrowserSDK } from "@phantom/browser-sdk";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  var PhantomContext = createContext(void 0);
6
6
  function PhantomProvider({ children, config, debugConfig }) {
7
- const [isConnected, setIsConnected] = useState(false);
8
- const [isConnecting, setIsConnecting] = useState(false);
9
- const [connectError, setConnectError] = useState(null);
10
- const [addresses, setAddresses] = useState([]);
11
- const [walletId, setWalletId] = useState(null);
12
- const [currentProviderType, setCurrentProviderType] = useState(config.providerType || null);
13
- const [isPhantomAvailable, setIsPhantomAvailable] = useState(false);
14
- const [sdk, setSdk] = useState(null);
15
7
  const memoizedConfig = useMemo(() => {
16
8
  return {
17
9
  ...config,
@@ -19,6 +11,16 @@ function PhantomProvider({ children, config, debugConfig }) {
19
11
  providerType: config.providerType || "embedded"
20
12
  };
21
13
  }, [config]);
14
+ const [isConnected, setIsConnected] = useState(false);
15
+ const [isConnecting, setIsConnecting] = useState(false);
16
+ const [connectError, setConnectError] = useState(null);
17
+ const [addresses, setAddresses] = useState([]);
18
+ const [walletId, setWalletId] = useState(null);
19
+ const [currentProviderType, setCurrentProviderType] = useState(
20
+ memoizedConfig.providerType || null
21
+ );
22
+ const [isPhantomAvailable, setIsPhantomAvailable] = useState(false);
23
+ const [sdk, setSdk] = useState(null);
22
24
  useEffect(() => {
23
25
  const sdkInstance = new BrowserSDK(memoizedConfig);
24
26
  const handleConnectStart = () => {
@@ -75,21 +77,21 @@ function PhantomProvider({ children, config, debugConfig }) {
75
77
  useEffect(() => {
76
78
  if (!sdk)
77
79
  return;
78
- const initialize = () => {
80
+ const initialize = async () => {
79
81
  try {
80
- const available = BrowserSDK.isPhantomInstalled();
82
+ const available = await BrowserSDK.isPhantomInstalled();
81
83
  setIsPhantomAvailable(available);
82
84
  } catch (err) {
83
85
  console.error("Error checking Phantom extension:", err);
84
86
  setIsPhantomAvailable(false);
85
87
  }
86
- if (config.autoConnect !== false) {
88
+ if (memoizedConfig.autoConnect !== false) {
87
89
  sdk.autoConnect().catch(() => {
88
90
  });
89
91
  }
90
92
  };
91
93
  initialize();
92
- }, [sdk, config.autoConnect]);
94
+ }, [sdk, memoizedConfig.autoConnect]);
93
95
  const value = useMemo(
94
96
  () => ({
95
97
  sdk,
@@ -101,16 +103,7 @@ function PhantomProvider({ children, config, debugConfig }) {
101
103
  currentProviderType,
102
104
  isPhantomAvailable
103
105
  }),
104
- [
105
- sdk,
106
- isConnected,
107
- isConnecting,
108
- connectError,
109
- addresses,
110
- walletId,
111
- currentProviderType,
112
- isPhantomAvailable
113
- ]
106
+ [sdk, isConnected, isConnecting, connectError, addresses, walletId, currentProviderType, isPhantomAvailable]
114
107
  );
115
108
  return /* @__PURE__ */ jsx(PhantomContext.Provider, { value, children });
116
109
  }
@@ -186,37 +179,34 @@ function useAccounts() {
186
179
 
187
180
  // src/hooks/useIsExtensionInstalled.ts
188
181
  import * as React from "react";
189
- import { BrowserSDK as BrowserSDK2 } from "@phantom/browser-sdk";
190
- var cachedIsInstalled = null;
182
+ import { waitForPhantomExtension } from "@phantom/browser-sdk";
191
183
  function useIsExtensionInstalled() {
192
- const { sdk } = usePhantom();
193
- const [isLoading, setIsLoading] = React.useState(cachedIsInstalled === null);
194
- const [isInstalled, setIsInstalled] = React.useState(cachedIsInstalled ?? false);
184
+ const [isLoading, setIsLoading] = React.useState(true);
185
+ const [isInstalled, setIsInstalled] = React.useState(false);
195
186
  React.useEffect(() => {
196
- if (!sdk) {
197
- setIsLoading(false);
198
- return;
199
- }
200
- if (cachedIsInstalled !== null) {
201
- setIsInstalled(cachedIsInstalled);
202
- setIsLoading(false);
203
- return;
204
- }
205
- const checkExtension = () => {
187
+ let isMounted = true;
188
+ const checkExtension = async () => {
206
189
  try {
207
190
  setIsLoading(true);
208
- const result = BrowserSDK2.isPhantomInstalled();
209
- cachedIsInstalled = result;
210
- setIsInstalled(result);
191
+ const result = await waitForPhantomExtension(3e3);
192
+ if (isMounted) {
193
+ setIsInstalled(result);
194
+ }
211
195
  } catch (error) {
212
- cachedIsInstalled = false;
213
- setIsInstalled(false);
196
+ if (isMounted) {
197
+ setIsInstalled(false);
198
+ }
214
199
  } finally {
215
- setIsLoading(false);
200
+ if (isMounted) {
201
+ setIsLoading(false);
202
+ }
216
203
  }
217
204
  };
218
205
  checkExtension();
219
- }, [sdk]);
206
+ return () => {
207
+ isMounted = false;
208
+ };
209
+ }, []);
220
210
  return { isLoading, isInstalled };
221
211
  }
222
212
 
@@ -253,53 +243,47 @@ function useAutoConfirm() {
253
243
  },
254
244
  [sdk, isInjected]
255
245
  );
256
- const disable = useCallback3(
257
- async () => {
258
- if (!sdk) {
259
- throw new Error("SDK not initialized");
260
- }
261
- if (!isInjected) {
262
- throw new Error("Auto-confirm is only available for injected (extension) providers");
263
- }
264
- try {
265
- setIsLoading(true);
266
- setError(null);
267
- await sdk.disableAutoConfirm();
268
- const newStatus = await sdk.getAutoConfirmStatus();
269
- setStatus(newStatus);
270
- } catch (err) {
271
- const error2 = err instanceof Error ? err : new Error("Unknown error occurred");
272
- setError(error2);
273
- throw error2;
274
- } finally {
275
- setIsLoading(false);
276
- }
277
- },
278
- [sdk, isInjected]
279
- );
280
- const refetch = useCallback3(
281
- async () => {
282
- if (!sdk || !isInjected) {
283
- return;
284
- }
285
- try {
286
- setIsLoading(true);
287
- setError(null);
288
- const [statusResult, supportedResult] = await Promise.all([
289
- sdk.getAutoConfirmStatus(),
290
- sdk.getSupportedAutoConfirmChains()
291
- ]);
292
- setStatus(statusResult);
293
- setSupportedChains(supportedResult);
294
- } catch (err) {
295
- const error2 = err instanceof Error ? err : new Error("Failed to fetch auto-confirm data");
296
- setError(error2);
297
- } finally {
298
- setIsLoading(false);
299
- }
300
- },
301
- [sdk, isInjected]
302
- );
246
+ const disable = useCallback3(async () => {
247
+ if (!sdk) {
248
+ throw new Error("SDK not initialized");
249
+ }
250
+ if (!isInjected) {
251
+ throw new Error("Auto-confirm is only available for injected (extension) providers");
252
+ }
253
+ try {
254
+ setIsLoading(true);
255
+ setError(null);
256
+ await sdk.disableAutoConfirm();
257
+ const newStatus = await sdk.getAutoConfirmStatus();
258
+ setStatus(newStatus);
259
+ } catch (err) {
260
+ const error2 = err instanceof Error ? err : new Error("Unknown error occurred");
261
+ setError(error2);
262
+ throw error2;
263
+ } finally {
264
+ setIsLoading(false);
265
+ }
266
+ }, [sdk, isInjected]);
267
+ const refetch = useCallback3(async () => {
268
+ if (!sdk || !isInjected) {
269
+ return;
270
+ }
271
+ try {
272
+ setIsLoading(true);
273
+ setError(null);
274
+ const [statusResult, supportedResult] = await Promise.all([
275
+ sdk.getAutoConfirmStatus(),
276
+ sdk.getSupportedAutoConfirmChains()
277
+ ]);
278
+ setStatus(statusResult);
279
+ setSupportedChains(supportedResult);
280
+ } catch (err) {
281
+ const error2 = err instanceof Error ? err : new Error("Failed to fetch auto-confirm data");
282
+ setError(error2);
283
+ } finally {
284
+ setIsLoading(false);
285
+ }
286
+ }, [sdk, isInjected]);
303
287
  useEffect3(() => {
304
288
  if (sdk && isInjected) {
305
289
  refetch();
@@ -324,6 +308,13 @@ function useAutoConfirm() {
324
308
  import { useCallback as useCallback4, useMemo as useMemo2 } from "react";
325
309
  function useSolana() {
326
310
  const { sdk, isConnected } = usePhantom();
311
+ const getSolanaChain = useCallback4(() => {
312
+ if (!sdk)
313
+ throw new Error("Phantom SDK not initialized.");
314
+ if (!sdk.isConnected())
315
+ throw new Error("Phantom SDK not connected. Call connect() first.");
316
+ return sdk.solana;
317
+ }, [sdk]);
327
318
  const solanaChain = useMemo2(() => {
328
319
  if (!sdk || !isConnected)
329
320
  return null;
@@ -333,41 +324,50 @@ function useSolana() {
333
324
  return null;
334
325
  }
335
326
  }, [sdk, isConnected]);
336
- const signMessage = useCallback4(async (message) => {
337
- if (!solanaChain)
338
- throw new Error("Solana chain not available. Ensure SDK is connected.");
339
- return solanaChain.signMessage(message);
340
- }, [solanaChain]);
341
- const signTransaction = useCallback4(async (transaction) => {
342
- if (!solanaChain)
343
- throw new Error("Solana chain not available. Ensure SDK is connected.");
344
- return solanaChain.signTransaction(transaction);
345
- }, [solanaChain]);
346
- const signAndSendTransaction = useCallback4(async (transaction) => {
347
- if (!solanaChain)
348
- throw new Error("Solana chain not available. Ensure SDK is connected.");
349
- return solanaChain.signAndSendTransaction(transaction);
350
- }, [solanaChain]);
351
- const connect = useCallback4(async (options) => {
352
- if (!solanaChain)
353
- throw new Error("Solana chain not available. Ensure SDK is connected.");
354
- return solanaChain.connect(options);
355
- }, [solanaChain]);
327
+ const signMessage = useCallback4(
328
+ async (message) => {
329
+ const chain = getSolanaChain();
330
+ return chain.signMessage(message);
331
+ },
332
+ [getSolanaChain]
333
+ );
334
+ const signTransaction = useCallback4(
335
+ async (transaction) => {
336
+ const chain = getSolanaChain();
337
+ return chain.signTransaction(transaction);
338
+ },
339
+ [getSolanaChain]
340
+ );
341
+ const signAndSendTransaction = useCallback4(
342
+ async (transaction) => {
343
+ const chain = getSolanaChain();
344
+ return chain.signAndSendTransaction(transaction);
345
+ },
346
+ [getSolanaChain]
347
+ );
348
+ const connect = useCallback4(
349
+ async (options) => {
350
+ const chain = getSolanaChain();
351
+ return chain.connect(options);
352
+ },
353
+ [getSolanaChain]
354
+ );
356
355
  const disconnect = useCallback4(async () => {
357
- if (!solanaChain)
358
- throw new Error("Solana chain not available. Ensure SDK is connected.");
359
- return solanaChain.disconnect();
360
- }, [solanaChain]);
361
- const switchNetwork = useCallback4(async (network) => {
362
- if (!solanaChain)
363
- throw new Error("Solana chain not available. Ensure SDK is connected.");
364
- return solanaChain.switchNetwork(network);
365
- }, [solanaChain]);
356
+ const chain = getSolanaChain();
357
+ return chain.disconnect();
358
+ }, [getSolanaChain]);
359
+ const switchNetwork = useCallback4(
360
+ async (network) => {
361
+ const chain = getSolanaChain();
362
+ return chain.switchNetwork?.(network);
363
+ },
364
+ [getSolanaChain]
365
+ );
366
366
  const getPublicKey = useCallback4(async () => {
367
- if (!solanaChain)
367
+ if (!sdk || !sdk.isConnected())
368
368
  return null;
369
- return solanaChain.getPublicKey();
370
- }, [solanaChain]);
369
+ return sdk.solana.getPublicKey();
370
+ }, [sdk]);
371
371
  return {
372
372
  // Chain instance for advanced usage
373
373
  solana: solanaChain,
@@ -389,6 +389,13 @@ function useSolana() {
389
389
  import { useCallback as useCallback5, useMemo as useMemo3 } from "react";
390
390
  function useEthereum() {
391
391
  const { sdk, isConnected } = usePhantom();
392
+ const getEthereumChain = useCallback5(() => {
393
+ if (!sdk)
394
+ throw new Error("Phantom SDK not initialized.");
395
+ if (!sdk.isConnected())
396
+ throw new Error("Phantom SDK not connected. Call connect() first.");
397
+ return sdk.ethereum;
398
+ }, [sdk]);
392
399
  const ethereumChain = useMemo3(() => {
393
400
  if (!sdk || !isConnected)
394
401
  return null;
@@ -398,50 +405,70 @@ function useEthereum() {
398
405
  return null;
399
406
  }
400
407
  }, [sdk, isConnected]);
401
- const request = useCallback5(async (args) => {
402
- if (!ethereumChain)
403
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
404
- return ethereumChain.request(args);
405
- }, [ethereumChain]);
406
- const signPersonalMessage = useCallback5(async (message, address) => {
407
- return request({
408
- method: "personal_sign",
409
- params: [message, address]
410
- });
411
- }, [request]);
412
- const sendTransaction = useCallback5(async (transaction) => {
413
- if (!ethereumChain)
414
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
415
- return ethereumChain.sendTransaction(transaction);
416
- }, [ethereumChain]);
417
- const switchChain = useCallback5(async (chainId) => {
418
- if (!ethereumChain)
419
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
420
- return ethereumChain.switchChain(chainId);
421
- }, [ethereumChain]);
408
+ const request = useCallback5(
409
+ async (args) => {
410
+ const chain = getEthereumChain();
411
+ return chain.request(args);
412
+ },
413
+ [getEthereumChain]
414
+ );
415
+ const signPersonalMessage = useCallback5(
416
+ async (message, address) => {
417
+ return request({
418
+ method: "personal_sign",
419
+ params: [message, address]
420
+ });
421
+ },
422
+ [request]
423
+ );
424
+ const signTransaction = useCallback5(
425
+ async (transaction) => {
426
+ const chain = getEthereumChain();
427
+ return chain.signTransaction(transaction);
428
+ },
429
+ [getEthereumChain]
430
+ );
431
+ const sendTransaction = useCallback5(
432
+ async (transaction) => {
433
+ const chain = getEthereumChain();
434
+ return chain.sendTransaction(transaction);
435
+ },
436
+ [getEthereumChain]
437
+ );
438
+ const switchChain = useCallback5(
439
+ async (chainId) => {
440
+ const chain = getEthereumChain();
441
+ return chain.switchChain(chainId);
442
+ },
443
+ [getEthereumChain]
444
+ );
422
445
  const getChainId = useCallback5(async () => {
423
- if (!ethereumChain)
424
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
425
- return ethereumChain.getChainId();
426
- }, [ethereumChain]);
446
+ const chain = getEthereumChain();
447
+ return chain.getChainId();
448
+ }, [getEthereumChain]);
427
449
  const getAccounts = useCallback5(async () => {
428
- if (!ethereumChain)
429
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
430
- return ethereumChain.getAccounts();
431
- }, [ethereumChain]);
432
- const signMessage = useCallback5(async (message) => {
433
- return request({
434
- method: "eth_sign",
435
- params: [await getAccounts().then((accounts) => accounts[0]), message]
436
- });
437
- }, [request, getAccounts]);
438
- const signTypedData = useCallback5(async (typedData) => {
439
- const accounts = await getAccounts();
440
- return request({
441
- method: "eth_signTypedData_v4",
442
- params: [accounts[0], JSON.stringify(typedData)]
443
- });
444
- }, [request, getAccounts]);
450
+ const chain = getEthereumChain();
451
+ return chain.getAccounts();
452
+ }, [getEthereumChain]);
453
+ const signMessage = useCallback5(
454
+ async (message) => {
455
+ return request({
456
+ method: "eth_sign",
457
+ params: [await getAccounts().then((accounts) => accounts[0]), message]
458
+ });
459
+ },
460
+ [request, getAccounts]
461
+ );
462
+ const signTypedData = useCallback5(
463
+ async (typedData) => {
464
+ const accounts = await getAccounts();
465
+ return request({
466
+ method: "eth_signTypedData_v4",
467
+ params: [accounts[0], JSON.stringify(typedData)]
468
+ });
469
+ },
470
+ [request, getAccounts]
471
+ );
445
472
  return {
446
473
  // Chain instance for advanced usage
447
474
  ethereum: ethereumChain,
@@ -450,6 +477,7 @@ function useEthereum() {
450
477
  // Convenient methods
451
478
  signPersonalMessage,
452
479
  signMessage,
480
+ signTransaction,
453
481
  signTypedData,
454
482
  sendTransaction,
455
483
  switchChain,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phantom/react-sdk",
3
- "version": "1.0.0-beta.0",
3
+ "version": "1.0.0-beta.2",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -26,9 +26,9 @@
26
26
  "prettier": "prettier --write \"src/**/*.{ts,tsx}\""
27
27
  },
28
28
  "dependencies": {
29
- "@phantom/browser-sdk": "^1.0.0-beta.0",
30
- "@phantom/chains": "^1.0.0-beta.0",
31
- "@phantom/constants": "^1.0.0-beta.0"
29
+ "@phantom/browser-sdk": "^1.0.0-beta.2",
30
+ "@phantom/chains": "^1.0.0-beta.2",
31
+ "@phantom/constants": "^1.0.0-beta.2"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@testing-library/dom": "^10.4.0",