@phantom/react-sdk 0.0.10 → 0.2.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
@@ -1,292 +1,612 @@
1
- # Phantom React SDK
1
+ # @phantom/react-sdk
2
2
 
3
- React hooks and components for integrating with Phantom wallet.
3
+ React hooks for integrating Phantom wallet functionality into React applications with native transaction support.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @phantom/react-sdk @phantom/browser-sdk
8
+ npm install @phantom/react-sdk
9
9
  ```
10
10
 
11
+ ## Dependencies
12
+
13
+ Install additional dependencies based on the networks you want to support:
14
+
15
+ | Network Support | Required Dependencies |
16
+ | --------------- | ---------------------------------- |
17
+ | Solana | `@solana/web3.js` OR `@solana/kit` |
18
+ | Ethereum/EVM | `viem` |
19
+ | Bitcoin | `bitcoinjs-lib` |
20
+ | Sui | `@mysten/sui.js` |
21
+
22
+ **Example for Solana + Ethereum support (using @solana/web3.js):**
23
+
24
+ ```bash
25
+ npm install @phantom/react-sdk @solana/web3.js viem
26
+ ```
27
+
28
+ **Example for Solana + Ethereum support (using @solana/kit):**
29
+
30
+ ```bash
31
+ npm install @phantom/react-sdk @solana/kit viem
32
+ ```
33
+
34
+ For complete dependency information and bundle optimization tips, see the [@phantom/browser-sdk documentation](../browser-sdk/README.md#bundle-optimization-tips).
35
+
11
36
  ## Quick Start
12
37
 
38
+ ### Basic Setup
39
+
13
40
  ```tsx
14
- import React from "react";
15
- import { PhantomProvider, useConnect } from "@phantom/react-sdk/solana";
16
- import { createSolanaPlugin } from "@phantom/browser-sdk/solana";
41
+ import { PhantomProvider } from "@phantom/react-sdk";
42
+ import { AddressType } from "@phantom/client";
17
43
 
18
44
  function App() {
19
45
  return (
20
- <PhantomProvider config={{ plugins: [createSolanaPlugin()] }}>
21
- <WalletComponent />
46
+ <PhantomProvider
47
+ config={{
48
+ providerType: "injected", // Uses Phantom browser extension
49
+ }}
50
+ >
51
+ <YourApp />
22
52
  </PhantomProvider>
23
53
  );
24
54
  }
55
+ ```
25
56
 
26
- function WalletComponent() {
27
- const { connect } = useConnect();
57
+ ### Embedded Wallet Setup
28
58
 
29
- const handleConnect = async () => {
30
- try {
31
- const connectedAccount = await connect();
32
- console.log("Wallet connected:", connectedAccount?.publicKey?.toString());
33
- } catch (error) {
34
- console.error("Connection failed:", error);
35
- }
36
- };
59
+ ```tsx
60
+ import { PhantomProvider } from "@phantom/react-sdk";
61
+ import { AddressType } from "@phantom/client";
37
62
 
63
+ function App() {
38
64
  return (
39
- <div>
40
- <button onClick={handleConnect}>Connect to Solana</button>
41
- </div>
65
+ <PhantomProvider
66
+ config={{
67
+ providerType: "embedded",
68
+ embeddedWalletType: "app-wallet", // or 'user-wallet'
69
+ addressTypes: [AddressType.solana, AddressType.ethereum],
70
+ apiBaseUrl: "https://api.phantom.com",
71
+ organizationId: "your-org-id",
72
+ }}
73
+ >
74
+ <YourApp />
75
+ </PhantomProvider>
42
76
  );
43
77
  }
78
+ ```
79
+
80
+ ## Provider Types
44
81
 
45
- export default App;
82
+ ### Injected Provider
83
+
84
+ Uses the Phantom browser extension installed by the user.
85
+
86
+ ```tsx
87
+ <PhantomProvider
88
+ config={{
89
+ providerType: "injected",
90
+ }}
91
+ >
92
+ <YourApp />
93
+ </PhantomProvider>
46
94
  ```
47
95
 
48
- ## API Reference
96
+ ### Embedded Provider
97
+
98
+ Creates non-custodial wallets embedded in your application.
49
99
 
50
- ### PhantomProvider
100
+ #### App Wallet (Recommended for most apps)
51
101
 
52
- The PhantomProvider component provides the Phantom context to child components.
102
+ - **New wallets** created per application
103
+ - **Unfunded** by default - you need to fund them
104
+ - **Independent** from user's existing Phantom wallet
53
105
 
54
106
  ```tsx
55
- import { PhantomProvider } from "@phantom/react-sdk";
56
- import { createSolanaPlugin } from "@phantom/browser-sdk/solana";
107
+ <PhantomProvider
108
+ config={{
109
+ providerType: "embedded",
110
+ embeddedWalletType: "app-wallet",
111
+ addressTypes: [AddressType.solana],
112
+ apiBaseUrl: "https://api.phantom.com",
113
+ organizationId: "your-org-id",
114
+ }}
115
+ >
116
+ <YourApp />
117
+ </PhantomProvider>
118
+ ```
119
+
120
+ #### User Wallet (For existing Phantom users)
121
+
122
+ - **Uses Phantom authentication** - user logs in with existing account
123
+ - **Potentially funded** - brings existing wallet balance
124
+ - **Connected** to user's Phantom ecosystem
57
125
 
58
- <PhantomProvider config={{ plugins: [createSolanaPlugin()] }}>{children}</PhantomProvider>;
126
+ ```tsx
127
+ <PhantomProvider
128
+ config={{
129
+ providerType: "embedded",
130
+ embeddedWalletType: "user-wallet",
131
+ addressTypes: [AddressType.solana, AddressType.ethereum],
132
+ apiBaseUrl: "https://api.phantom.com",
133
+ organizationId: "your-org-id",
134
+ }}
135
+ >
136
+ <YourApp />
137
+ </PhantomProvider>
59
138
  ```
60
139
 
61
- ### usePhantom
140
+ ## Solana Provider Configuration
62
141
 
63
- The `usePhantom` hoo provides access to the phantom instance. With Phantom instance you can call browser-sdk methods directly.
142
+ When using `AddressType.solana`, you can choose between two Solana libraries:
64
143
 
65
- ## Solana API Reference
144
+ ```tsx
145
+ <PhantomProvider
146
+ config={{
147
+ providerType: "embedded",
148
+ addressTypes: [AddressType.solana],
149
+ solanaProvider: "web3js", // or 'kit'
150
+ apiBaseUrl: "https://api.phantom.com",
151
+ organizationId: "your-org-id",
152
+ }}
153
+ >
154
+ <YourApp />
155
+ </PhantomProvider>
156
+ ```
66
157
 
67
- ### useConnect (Solana)
158
+ **Provider Options:**
68
159
 
69
- The `useConnect` hook provides a function to connect to the Phantom wallet for Solana.
160
+ - `'web3js'` (default) - Uses `@solana/web3.js` library
161
+ - `'kit'` - Uses `@solana/kit` library (modern, TypeScript-first)
70
162
 
71
- #### Props
163
+ **When to use each:**
72
164
 
73
- - `autoConnect?: boolean` (optional) - If `true`, attempts to connect to the wallet automatically when the component mounts. Defaults to `false`.
165
+ - **@solana/web3.js**: Better ecosystem compatibility, wider community support
166
+ - **@solana/kit**: Better TypeScript support, modern architecture, smaller bundle size
74
167
 
75
- #### Return Value
168
+ ## Available Hooks
76
169
 
77
- The hook returns an object with the following property:
170
+ ### useConnect
78
171
 
79
- - `connect: () => Promise<ConnectResponse>` - An asynchronous function that initiates the connection process. Returns a promise that resolves with the connection response (e.g., `{ publicKey: string }`) or rejects if connection fails.
172
+ Connect to wallet:
80
173
 
81
174
  ```tsx
82
- import { useConnect } from "@phantom/react-sdk/solana"; // Or '@phantom/react-sdk/solana' if specific
175
+ import { useConnect } from "@phantom/react-sdk";
83
176
 
84
- function MyComponent() {
85
- const { connect } = useConnect({ autoConnect: true });
177
+ function ConnectButton() {
178
+ const { connect, isLoading, error } = useConnect();
86
179
 
87
- const handleConnectClick = async () => {
180
+ const handleConnect = async () => {
88
181
  try {
89
- const res = await connect();
90
- console.log("Connected:", res.publicKey.toString());
182
+ const { walletId, addresses } = await connect();
183
+ console.log("Connected addresses:", addresses);
91
184
  } catch (err) {
92
- console.error("Connection error:", err);
185
+ console.error("Failed to connect:", err);
93
186
  }
94
187
  };
95
- // ...
188
+
189
+ return (
190
+ <button onClick={handleConnect} disabled={isLoading}>
191
+ {isLoading ? "Connecting..." : "Connect Wallet"}
192
+ </button>
193
+ );
96
194
  }
97
195
  ```
98
196
 
99
- ### useDisconnect (Solana)
197
+ ### useAccounts
100
198
 
101
- The `useDisconnect` hook provides a function to disconnect from the Phantom wallet for Solana.
199
+ Get connected wallet addresses:
200
+
201
+ ```tsx
202
+ import { useAccounts } from "@phantom/react-sdk";
102
203
 
103
- #### Return Value
204
+ function WalletAddresses() {
205
+ const addresses = useAccounts();
206
+
207
+ if (!addresses) {
208
+ return <div>Not connected</div>;
209
+ }
210
+
211
+ return (
212
+ <div>
213
+ {addresses.map((addr, index) => (
214
+ <div key={index}>
215
+ <strong>{addr.addressType}:</strong> {addr.address}
216
+ </div>
217
+ ))}
218
+ </div>
219
+ );
220
+ }
221
+ ```
104
222
 
105
- The hook returns an object with the following property:
223
+ ### useIsExtensionInstalled
106
224
 
107
- - `disconnect: () => Promise<void>` - An asynchronous function that initiates the disconnection process. Returns a promise that resolves when disconnection is complete or rejects if disconnection fails.
225
+ Check if the Phantom browser extension is installed (for injected provider):
108
226
 
109
227
  ```tsx
110
- import { useDisconnect } from "@phantom/react-sdk/solana";
228
+ import { useIsExtensionInstalled } from "@phantom/react-sdk";
111
229
 
112
- function MyComponent() {
113
- const { disconnect } = useDisconnect();
230
+ function ExtensionStatus() {
231
+ const { isLoading, isInstalled } = useIsExtensionInstalled();
114
232
 
115
- const handleDisconnectClick = async () => {
116
- try {
117
- await disconnect();
118
- console.log("Disconnected");
119
- } catch (err) {
120
- console.error("Disconnection error:", err);
121
- }
122
- };
123
- // ...
233
+ if (isLoading) {
234
+ return <div>Checking for Phantom extension...</div>;
235
+ }
236
+
237
+ return (
238
+ <div>
239
+ {isInstalled ? (
240
+ <p>✅ Phantom extension is installed!</p>
241
+ ) : (
242
+ <p>
243
+ ❌ Phantom extension not found.{" "}
244
+ <a href="https://phantom.app/download" target="_blank">
245
+ Install here
246
+ </a>
247
+ </p>
248
+ )}
249
+ </div>
250
+ );
124
251
  }
125
252
  ```
126
253
 
127
- ### useAccount
254
+ **Features:**
128
255
 
129
- The `useAccount` hook provides access the currently connected address
256
+ - **Session-based caching**: Result is cached during the browser session to avoid redundant checks
257
+ - **Automatic detection**: Runs automatically when the hook is first used
258
+ - **Loading states**: Provides `isLoading` during the initial check
259
+ - **Performance optimized**: Subsequent calls return cached result instantly
130
260
 
131
- #### Return Value
261
+ **Use cases:**
132
262
 
133
- The hook returns a string with the currently connected address or undefined when account is not connected.
263
+ - Show installation prompts for users without the extension
264
+ - Conditionally render UI based on extension availability
265
+ - Provide fallback options when extension is not installed
134
266
 
135
- ````tsx
267
+ ### useDisconnect
136
268
 
137
- ### useSignIn (Solana)
269
+ Disconnect from wallet:
138
270
 
139
- The `useSignIn` hook provides a function to initiate a sign-in request to the Phantom wallet for Solana. This is compliant with SIP-001 (Sign In With Solana).
271
+ ```tsx
272
+ import { useDisconnect } from "@phantom/react-sdk";
273
+
274
+ function DisconnectButton() {
275
+ const { disconnect, isLoading } = useDisconnect();
140
276
 
141
- #### Return Value
277
+ return (
278
+ <button onClick={disconnect} disabled={isLoading}>
279
+ {isLoading ? "Disconnecting..." : "Disconnect"}
280
+ </button>
281
+ );
282
+ }
283
+ ```
142
284
 
143
- The hook returns an object with the following property:
285
+ ### useSignMessage
144
286
 
145
- - `signIn: (signInData: SolanaSignInData) => Promise<{ address: string; signature: Uint8Array; signedMessage: Uint8Array }>` - An asynchronous function that initiates the sign-in process. `SolanaSignInData` is a type imported from `@phantom/browser-sdk/solana`. Returns a promise that resolves with the `address` (string), `signature` (Uint8Array), and `signedMessage` (Uint8Array), or rejects if the sign-in fails.
287
+ Sign messages with native string input:
146
288
 
147
289
  ```tsx
148
- import { useSignIn } from "@phantom/react-sdk/solana";
149
- import { SolanaSignInData } from "@phantom/browser-sdk/solana"; // This type might be needed from the browser-sdk
290
+ import { useSignMessage, NetworkId } from "@phantom/react-sdk";
150
291
 
151
- function MyComponent() {
152
- const { signIn } = useSignIn();
153
-
154
- const handleSignInClick = async () => {
155
- // Construct SolanaSignInData according to your needs
156
- // This typically includes the domain and a statement for the user.
157
- const signInData: SolanaSignInData = {
158
- domain: window.location.host,
159
- statement: "Please sign in to access exclusive features.",
160
- // Other fields like `nonce`, `chainId`, `resources` can be added as per SIP-001
161
- };
292
+ function SignMessage() {
293
+ const { signMessage, isLoading, error } = useSignMessage();
162
294
 
295
+ const handleSign = async () => {
163
296
  try {
164
- const result = await signIn(signInData);
165
- console.log("Sign In successful. Address:", result.address.toString());
166
- // You can now verify the signature and signedMessage on your backend
167
- // Handle successful sign-in (e.g., update UI, set user session)
297
+ const signature = await signMessage({
298
+ message: "Hello from Phantom!",
299
+ networkId: NetworkId.SOLANA_MAINNET,
300
+ });
301
+ console.log("Signature:", signature);
168
302
  } catch (err) {
169
- console.error("Sign In error:", err);
170
- // Handle sign-in error (e.g., show error message to user)
303
+ console.error("Failed to sign:", err);
171
304
  }
172
305
  };
173
306
 
174
- return <button onClick={handleSignInClick}>Sign In with Solana</button>;
307
+ return (
308
+ <button onClick={handleSign} disabled={isLoading}>
309
+ {isLoading ? "Signing..." : "Sign Message"}
310
+ </button>
311
+ );
175
312
  }
176
- ````
313
+ ```
177
314
 
178
- ### useSignMessage (Solana)
315
+ ### useSignAndSendTransaction
179
316
 
180
- The `useSignMessage` hook provides a function to prompt the user to sign an arbitrary message with their Solana account.
317
+ #### Solana Transaction
181
318
 
182
- #### Return Value
319
+ ```tsx
320
+ import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
321
+ import { Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
322
+
323
+ function SendSolanaTransaction() {
324
+ const { signAndSendTransaction, isLoading, error } = useSignAndSendTransaction();
325
+
326
+ const handleSend = async () => {
327
+ // Create native Solana transaction - no encoding needed!
328
+ const transaction = new Transaction().add(
329
+ SystemProgram.transfer({
330
+ fromPubkey: new PublicKey(fromAddress),
331
+ toPubkey: new PublicKey(toAddress),
332
+ lamports: 0.001 * LAMPORTS_PER_SOL,
333
+ }),
334
+ );
183
335
 
184
- The hook returns an object with the following property:
336
+ try {
337
+ const result = await signAndSendTransaction({
338
+ networkId: NetworkId.SOLANA_MAINNET,
339
+ transaction: transaction, // Native Transaction object!
340
+ });
341
+ console.log("Transaction sent:", result.rawTransaction);
342
+ } catch (err) {
343
+ console.error("Failed to send:", err);
344
+ }
345
+ };
185
346
 
186
- - `signMessage: (message: Uint8Array, display?: 'utf8' | 'hex') => Promise<{ signature: Uint8Array; publicKey: string }>` - An asynchronous function that prompts the user to sign a message. The `message` must be a `Uint8Array`. The optional `display` parameter can be 'utf8' (default) or 'hex' to suggest how the wallet should display the message bytes. Returns a promise that resolves with the `signature` (Uint8Array) and `publicKey` (string) of the signer, or rejects if signing fails.
347
+ return (
348
+ <button onClick={handleSend} disabled={isLoading}>
349
+ {isLoading ? "Sending..." : "Send SOL"}
350
+ </button>
351
+ );
352
+ }
353
+ ```
354
+
355
+ #### Ethereum Transaction (with Viem)
187
356
 
188
357
  ```tsx
189
- import { useSignMessage } from "@phantom/react-sdk/solana";
358
+ import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
359
+ import { parseEther, parseGwei } from "viem";
190
360
 
191
- function MyComponent() {
192
- const { signMessage } = useSignMessage();
361
+ function SendEthereumTransaction() {
362
+ const { signAndSendTransaction, isLoading } = useSignAndSendTransaction();
193
363
 
194
- const handleSignMessage = async () => {
195
- const messageToSign = "Please confirm your action by signing this message.";
196
- const messageBytes = new TextEncoder().encode(messageToSign);
364
+ const handleSend = async () => {
197
365
  try {
198
- const { signature, publicKey } = await signMessage(messageBytes, "utf8");
199
- console.log("Message signed successfully!");
200
- console.log("Signature:", signature);
201
- console.log("Public Key:", publicKey);
202
- // You can now verify this signature on a backend or use it as needed.
366
+ const result = await signAndSendTransaction({
367
+ networkId: NetworkId.ETHEREUM_MAINNET,
368
+ transaction: {
369
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
370
+ value: parseEther("0.001"), // 0.001 ETH
371
+ gas: 21000n,
372
+ gasPrice: parseGwei("20"), // 20 gwei
373
+ },
374
+ });
375
+ console.log("Transaction sent:", result);
203
376
  } catch (err) {
204
- console.error("Sign message error:", err);
205
- // Handle error (e.g., user rejected, wallet error)
377
+ console.error("Failed to send:", err);
206
378
  }
207
379
  };
208
380
 
209
- return <button onClick={handleSignMessage}>Sign Message</button>;
381
+ return (
382
+ <button onClick={handleSend} disabled={isLoading}>
383
+ {isLoading ? "Sending..." : "Send ETH"}
384
+ </button>
385
+ );
210
386
  }
211
387
  ```
212
388
 
213
- ### useSignAndSendTransaction (Solana)
389
+ ## Network Support
390
+
391
+ ### Supported Networks
214
392
 
215
- The `useSignAndSendTransaction` hook prompts the user to sign **and** send a Kit-style transaction.
393
+ The SDK automatically determines the transaction type from the NetworkId:
216
394
 
217
- #### Return Value
395
+ #### Solana
218
396
 
219
- The hook returns an object with the following property:
397
+ - `NetworkId.SOLANA_MAINNET`
398
+ - `NetworkId.SOLANA_DEVNET`
399
+ - `NetworkId.SOLANA_TESTNET`
400
+
401
+ #### Ethereum/EVM
402
+
403
+ - `NetworkId.ETHEREUM_MAINNET`
404
+ - `NetworkId.ETHEREUM_SEPOLIA`
405
+ - `NetworkId.POLYGON_MAINNET`
406
+ - `NetworkId.ARBITRUM_ONE`
407
+ - `NetworkId.OPTIMISM_MAINNET`
408
+ - `NetworkId.BASE_MAINNET`
409
+
410
+ #### Bitcoin
411
+
412
+ - `NetworkId.BITCOIN_MAINNET`
413
+ - `NetworkId.BITCOIN_TESTNET`
414
+
415
+ #### Sui
416
+
417
+ - `NetworkId.SUI_MAINNET`
418
+ - `NetworkId.SUI_TESTNET`
419
+ - `NetworkId.SUI_DEVNET`
420
+
421
+ ### Provider Network Support
422
+
423
+ | Provider Type | Network Support |
424
+ | ------------- | ----------------------------------------------- |
425
+ | **Injected** | All networks supported by Phantom extension |
426
+ | **Embedded** | All networks based on configured `addressTypes` |
427
+
428
+ ## Transaction Examples
429
+
430
+ ### Solana with @solana/web3.js
431
+
432
+ ```tsx
433
+ import { Transaction, SystemProgram, PublicKey } from "@solana/web3.js";
434
+ import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
435
+
436
+ function SolanaExample() {
437
+ const { signAndSendTransaction } = useSignAndSendTransaction();
438
+
439
+ const sendTransaction = async () => {
440
+ const transaction = new Transaction().add(
441
+ SystemProgram.transfer({
442
+ fromPubkey: new PublicKey(fromAddress),
443
+ toPubkey: new PublicKey(toAddress),
444
+ lamports: 1000000, // 0.001 SOL
445
+ }),
446
+ );
447
+
448
+ // No serialization or encoding needed!
449
+ const result = await signAndSendTransaction({
450
+ networkId: NetworkId.SOLANA_MAINNET,
451
+ transaction,
452
+ });
453
+ };
454
+ }
455
+ ```
220
456
 
221
- - `signAndSendTransaction(transaction: Transaction): Promise<{ signature: string; publicKey?: string }>` – accepts a `Transaction` built with **`@solana/kit`** and returns the confirmed signature.
457
+ ### Solana with @solana/kit
222
458
 
223
459
  ```tsx
224
- import { useSignAndSendTransaction } from "@phantom/react-sdk/solana"; // scoped import is fine
225
460
  import {
226
461
  createSolanaRpc,
462
+ pipe,
227
463
  createTransactionMessage,
228
464
  setTransactionMessageFeePayer,
229
465
  setTransactionMessageLifetimeUsingBlockhash,
230
- pipe,
231
466
  address,
232
467
  compileTransaction,
233
468
  } from "@solana/kit";
469
+ import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
234
470
 
235
- function MyComponent() {
471
+ function SolanaKitExample() {
236
472
  const { signAndSendTransaction } = useSignAndSendTransaction();
237
473
 
238
- const handlePayment = async (publicKey: string) => {
239
- // 0️⃣ Ensure the wallet is connected and we have a fee-payer address
240
- if (!publicKey) return console.error("Wallet not connected");
474
+ const sendTransaction = async () => {
475
+ const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
476
+ const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
241
477
 
242
- try {
243
- // 1️⃣ Fetch a recent blockhash
244
- const rpc = createSolanaRpc("https://api.devnet.solana.com");
245
- const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
246
-
247
- // 2️⃣ Build a minimal v0 transaction message (no instructions – demo only)
248
- const txMessage = pipe(
249
- createTransactionMessage({ version: 0 }),
250
- tx => setTransactionMessageFeePayer(address(publicKey), tx),
251
- tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
252
- );
253
-
254
- const transaction = compileTransaction(txMessage);
255
-
256
- // 3️⃣ Prompt the user to sign and send
257
- const { signature } = await signAndSendTransaction(transaction);
258
- console.log("Transaction signature:", signature);
259
- } catch (err) {
260
- console.error("Transaction error:", err);
261
- }
262
- };
478
+ const transactionMessage = pipe(
479
+ createTransactionMessage({ version: 0 }),
480
+ tx => setTransactionMessageFeePayer(address(userPublicKey), tx),
481
+ tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
482
+ );
263
483
 
264
- return <button onClick={() => handlePayment("YOUR_CONNECTED_WALLET_PUBLIC_KEY")}>Send 0.001 SOL</button>;
484
+ const transaction = compileTransaction(transactionMessage);
485
+
486
+ const result = await signAndSendTransaction({
487
+ networkId: NetworkId.SOLANA_MAINNET,
488
+ transaction,
489
+ });
490
+ };
265
491
  }
266
492
  ```
267
493
 
268
- ### useAccountEffect
494
+ ### Ethereum with Viem
269
495
 
270
- The `useAccountEffect` hook provides easy way to subscribe to events like `connect`, `disconnect` and `accountChanged`. You can subscribe by calling the hook and declaring event callbacks you want to react to.
496
+ ```tsx
497
+ import { parseEther, parseGwei, encodeFunctionData } from "viem";
498
+ import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
271
499
 
272
- Example:
500
+ function EthereumExample() {
501
+ const { signAndSendTransaction } = useSignAndSendTransaction();
273
502
 
274
- ```tsx
275
- useAccountEffect({
276
- onConnect: data => {
277
- console.log("Connected to Phantom with public key:", data.publicKey);
278
- },
279
- onDisconnect: () => {
280
- console.log("Disconnected from Phantom");
281
- },
282
- onAccountChanged: data => {
283
- console.log("Account changed to:", data.publicKey);
284
- },
285
- });
503
+ const sendEth = async () => {
504
+ const result = await signAndSendTransaction({
505
+ networkId: NetworkId.ETHEREUM_MAINNET,
506
+ transaction: {
507
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
508
+ value: parseEther("1"), // 1 ETH
509
+ gas: 21000n,
510
+ gasPrice: parseGwei("20"), // 20 gwei
511
+ },
512
+ });
513
+ };
514
+
515
+ const sendToken = async () => {
516
+ const result = await signAndSendTransaction({
517
+ networkId: NetworkId.ETHEREUM_MAINNET,
518
+ transaction: {
519
+ to: tokenContractAddress,
520
+ data: encodeFunctionData({
521
+ abi: erc20Abi,
522
+ functionName: "transfer",
523
+ args: [recipientAddress, parseEther("100")],
524
+ }),
525
+ gas: 50000n,
526
+ maxFeePerGas: parseGwei("30"),
527
+ maxPriorityFeePerGas: parseGwei("2"),
528
+ },
529
+ });
530
+ };
531
+ }
286
532
  ```
287
533
 
288
- ## Extension API Reference
534
+ ## Advanced Usage
535
+
536
+ ### Multi-Chain Application
289
537
 
290
- ### useIsInstalled
538
+ ```tsx
539
+ import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
540
+ import { Transaction, SystemProgram, PublicKey } from "@solana/web3.js";
541
+ import { parseEther } from "viem";
542
+
543
+ function MultiChainWallet() {
544
+ const { signAndSendTransaction } = useSignAndSendTransaction();
545
+
546
+ const sendSolana = async () => {
547
+ const transaction = new Transaction().add(
548
+ SystemProgram.transfer({
549
+ fromPubkey: new PublicKey(solanaAddress),
550
+ toPubkey: new PublicKey(recipient),
551
+ lamports: 1000000,
552
+ }),
553
+ );
554
+
555
+ return await signAndSendTransaction({
556
+ networkId: NetworkId.SOLANA_MAINNET,
557
+ transaction,
558
+ });
559
+ };
560
+
561
+ const sendEthereum = async () => {
562
+ return await signAndSendTransaction({
563
+ networkId: NetworkId.ETHEREUM_MAINNET,
564
+ transaction: {
565
+ to: recipient,
566
+ value: parseEther("0.1"),
567
+ gas: 21000n,
568
+ },
569
+ });
570
+ };
571
+
572
+ return (
573
+ <div>
574
+ <button onClick={sendSolana}>Send SOL</button>
575
+ <button onClick={sendEthereum}>Send ETH</button>
576
+ </div>
577
+ );
578
+ }
579
+ ```
580
+
581
+ ## Hooks Reference
582
+
583
+ Quick reference of all available hooks:
584
+
585
+ | Hook | Purpose | Returns |
586
+ | --------------------------- | ----------------------------------- | ----------------------------------------------- |
587
+ | `useConnect` | Connect to wallet | `{ connect, isConnecting, error }` |
588
+ | `useAccounts` | Get wallet addresses | `WalletAddress[]` or `null` |
589
+ | `useIsExtensionInstalled` | Check extension status | `{ isLoading, isInstalled }` |
590
+ | `useDisconnect` | Disconnect from wallet | `{ disconnect, isDisconnecting }` |
591
+ | `useSignMessage` | Sign text messages | `{ signMessage, isSigning, error }` |
592
+ | `useSignAndSendTransaction` | Sign and send transactions | `{ signAndSendTransaction, isSigning, error }` |
593
+ | `useCreateUserOrganization` | Create user organization (embedded) | `{ createUserOrganization, isCreating, error }` |
594
+ | `usePhantom` | Get provider context | `{ isConnected, isReady, currentProviderType }` |
595
+
596
+ ## Configuration Reference
597
+
598
+ ```typescript
599
+ interface PhantomSDKConfig {
600
+ providerType: "injected" | "embedded";
601
+
602
+ // Required for embedded provider only
603
+ addressTypes?: AddressType[]; // Networks to enable
604
+ apiBaseUrl?: string; // Phantom API base URL
605
+ organizationId?: string; // Your organization ID
606
+ authUrl?: string; // Custom auth URL (optional)
607
+ embeddedWalletType?: "app-wallet" | "user-wallet"; // Wallet type
608
+ solanaProvider?: "web3js" | "kit"; // Solana library choice (default: 'web3js')
609
+ }
610
+ ```
291
611
 
292
- The `useIsInstalled` hook provides a function to check whether the phantom extension is installed
612
+ For more details, examples, and bundle optimization tips, see the [@phantom/browser-sdk documentation](../browser-sdk/README.md).