@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 +484 -164
- package/dist/index.d.ts +72 -15
- package/dist/index.js +311 -17
- package/dist/index.mjs +320 -5
- package/package.json +7 -20
- package/dist/auto-confirm/index.d.ts +0 -44
- package/dist/auto-confirm/index.js +0 -182
- package/dist/auto-confirm/index.mjs +0 -137
- package/dist/chunk-5KSEZ3MC.mjs +0 -25
- package/dist/extension/index.d.ts +0 -5
- package/dist/extension/index.js +0 -68
- package/dist/extension/index.mjs +0 -22
- package/dist/solana/index.d.ts +0 -64
- package/dist/solana/index.js +0 -230
- package/dist/solana/index.mjs +0 -178
package/README.md
CHANGED
|
@@ -1,292 +1,612 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @phantom/react-sdk
|
|
2
2
|
|
|
3
|
-
React hooks
|
|
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
|
|
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
|
|
15
|
-
import {
|
|
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
|
|
21
|
-
|
|
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
|
-
|
|
27
|
-
const { connect } = useConnect();
|
|
57
|
+
### Embedded Wallet Setup
|
|
28
58
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
96
|
+
### Embedded Provider
|
|
97
|
+
|
|
98
|
+
Creates non-custodial wallets embedded in your application.
|
|
49
99
|
|
|
50
|
-
|
|
100
|
+
#### App Wallet (Recommended for most apps)
|
|
51
101
|
|
|
52
|
-
|
|
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
|
-
|
|
56
|
-
|
|
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
|
-
|
|
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
|
-
|
|
140
|
+
## Solana Provider Configuration
|
|
62
141
|
|
|
63
|
-
|
|
142
|
+
When using `AddressType.solana`, you can choose between two Solana libraries:
|
|
64
143
|
|
|
65
|
-
|
|
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
|
-
|
|
158
|
+
**Provider Options:**
|
|
68
159
|
|
|
69
|
-
|
|
160
|
+
- `'web3js'` (default) - Uses `@solana/web3.js` library
|
|
161
|
+
- `'kit'` - Uses `@solana/kit` library (modern, TypeScript-first)
|
|
70
162
|
|
|
71
|
-
|
|
163
|
+
**When to use each:**
|
|
72
164
|
|
|
73
|
-
-
|
|
165
|
+
- **@solana/web3.js**: Better ecosystem compatibility, wider community support
|
|
166
|
+
- **@solana/kit**: Better TypeScript support, modern architecture, smaller bundle size
|
|
74
167
|
|
|
75
|
-
|
|
168
|
+
## Available Hooks
|
|
76
169
|
|
|
77
|
-
|
|
170
|
+
### useConnect
|
|
78
171
|
|
|
79
|
-
|
|
172
|
+
Connect to wallet:
|
|
80
173
|
|
|
81
174
|
```tsx
|
|
82
|
-
import { useConnect } from "@phantom/react-sdk
|
|
175
|
+
import { useConnect } from "@phantom/react-sdk";
|
|
83
176
|
|
|
84
|
-
function
|
|
85
|
-
const { connect } = useConnect(
|
|
177
|
+
function ConnectButton() {
|
|
178
|
+
const { connect, isLoading, error } = useConnect();
|
|
86
179
|
|
|
87
|
-
const
|
|
180
|
+
const handleConnect = async () => {
|
|
88
181
|
try {
|
|
89
|
-
const
|
|
90
|
-
console.log("Connected:",
|
|
182
|
+
const { walletId, addresses } = await connect();
|
|
183
|
+
console.log("Connected addresses:", addresses);
|
|
91
184
|
} catch (err) {
|
|
92
|
-
console.error("
|
|
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
|
-
###
|
|
197
|
+
### useAccounts
|
|
100
198
|
|
|
101
|
-
|
|
199
|
+
Get connected wallet addresses:
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
import { useAccounts } from "@phantom/react-sdk";
|
|
102
203
|
|
|
103
|
-
|
|
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
|
-
|
|
223
|
+
### useIsExtensionInstalled
|
|
106
224
|
|
|
107
|
-
|
|
225
|
+
Check if the Phantom browser extension is installed (for injected provider):
|
|
108
226
|
|
|
109
227
|
```tsx
|
|
110
|
-
import {
|
|
228
|
+
import { useIsExtensionInstalled } from "@phantom/react-sdk";
|
|
111
229
|
|
|
112
|
-
function
|
|
113
|
-
const {
|
|
230
|
+
function ExtensionStatus() {
|
|
231
|
+
const { isLoading, isInstalled } = useIsExtensionInstalled();
|
|
114
232
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
254
|
+
**Features:**
|
|
128
255
|
|
|
129
|
-
|
|
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
|
-
|
|
261
|
+
**Use cases:**
|
|
132
262
|
|
|
133
|
-
|
|
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
|
-
|
|
267
|
+
### useDisconnect
|
|
136
268
|
|
|
137
|
-
|
|
269
|
+
Disconnect from wallet:
|
|
138
270
|
|
|
139
|
-
|
|
271
|
+
```tsx
|
|
272
|
+
import { useDisconnect } from "@phantom/react-sdk";
|
|
273
|
+
|
|
274
|
+
function DisconnectButton() {
|
|
275
|
+
const { disconnect, isLoading } = useDisconnect();
|
|
140
276
|
|
|
141
|
-
|
|
277
|
+
return (
|
|
278
|
+
<button onClick={disconnect} disabled={isLoading}>
|
|
279
|
+
{isLoading ? "Disconnecting..." : "Disconnect"}
|
|
280
|
+
</button>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
142
284
|
|
|
143
|
-
|
|
285
|
+
### useSignMessage
|
|
144
286
|
|
|
145
|
-
|
|
287
|
+
Sign messages with native string input:
|
|
146
288
|
|
|
147
289
|
```tsx
|
|
148
|
-
import {
|
|
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
|
|
152
|
-
const {
|
|
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
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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("
|
|
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
|
|
307
|
+
return (
|
|
308
|
+
<button onClick={handleSign} disabled={isLoading}>
|
|
309
|
+
{isLoading ? "Signing..." : "Sign Message"}
|
|
310
|
+
</button>
|
|
311
|
+
);
|
|
175
312
|
}
|
|
176
|
-
|
|
313
|
+
```
|
|
177
314
|
|
|
178
|
-
###
|
|
315
|
+
### useSignAndSendTransaction
|
|
179
316
|
|
|
180
|
-
|
|
317
|
+
#### Solana Transaction
|
|
181
318
|
|
|
182
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
358
|
+
import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
|
|
359
|
+
import { parseEther, parseGwei } from "viem";
|
|
190
360
|
|
|
191
|
-
function
|
|
192
|
-
const {
|
|
361
|
+
function SendEthereumTransaction() {
|
|
362
|
+
const { signAndSendTransaction, isLoading } = useSignAndSendTransaction();
|
|
193
363
|
|
|
194
|
-
const
|
|
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
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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("
|
|
205
|
-
// Handle error (e.g., user rejected, wallet error)
|
|
377
|
+
console.error("Failed to send:", err);
|
|
206
378
|
}
|
|
207
379
|
};
|
|
208
380
|
|
|
209
|
-
return
|
|
381
|
+
return (
|
|
382
|
+
<button onClick={handleSend} disabled={isLoading}>
|
|
383
|
+
{isLoading ? "Sending..." : "Send ETH"}
|
|
384
|
+
</button>
|
|
385
|
+
);
|
|
210
386
|
}
|
|
211
387
|
```
|
|
212
388
|
|
|
213
|
-
|
|
389
|
+
## Network Support
|
|
390
|
+
|
|
391
|
+
### Supported Networks
|
|
214
392
|
|
|
215
|
-
The
|
|
393
|
+
The SDK automatically determines the transaction type from the NetworkId:
|
|
216
394
|
|
|
217
|
-
####
|
|
395
|
+
#### Solana
|
|
218
396
|
|
|
219
|
-
|
|
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
|
-
|
|
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
|
|
471
|
+
function SolanaKitExample() {
|
|
236
472
|
const { signAndSendTransaction } = useSignAndSendTransaction();
|
|
237
473
|
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
494
|
+
### Ethereum with Viem
|
|
269
495
|
|
|
270
|
-
|
|
496
|
+
```tsx
|
|
497
|
+
import { parseEther, parseGwei, encodeFunctionData } from "viem";
|
|
498
|
+
import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
|
|
271
499
|
|
|
272
|
-
|
|
500
|
+
function EthereumExample() {
|
|
501
|
+
const { signAndSendTransaction } = useSignAndSendTransaction();
|
|
273
502
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
##
|
|
534
|
+
## Advanced Usage
|
|
535
|
+
|
|
536
|
+
### Multi-Chain Application
|
|
289
537
|
|
|
290
|
-
|
|
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
|
-
|
|
612
|
+
For more details, examples, and bundle optimization tips, see the [@phantom/browser-sdk documentation](../browser-sdk/README.md).
|