@phantom/react-sdk 0.0.10 → 0.1.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 +475 -165
- 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,602 @@
|
|
|
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>❌ Phantom extension not found. <a href="https://phantom.app/download" target="_blank">Install here</a></p>
|
|
243
|
+
)}
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
124
246
|
}
|
|
125
247
|
```
|
|
126
248
|
|
|
127
|
-
|
|
249
|
+
**Features:**
|
|
250
|
+
- **Session-based caching**: Result is cached during the browser session to avoid redundant checks
|
|
251
|
+
- **Automatic detection**: Runs automatically when the hook is first used
|
|
252
|
+
- **Loading states**: Provides `isLoading` during the initial check
|
|
253
|
+
- **Performance optimized**: Subsequent calls return cached result instantly
|
|
128
254
|
|
|
129
|
-
|
|
255
|
+
**Use cases:**
|
|
256
|
+
- Show installation prompts for users without the extension
|
|
257
|
+
- Conditionally render UI based on extension availability
|
|
258
|
+
- Provide fallback options when extension is not installed
|
|
130
259
|
|
|
131
|
-
|
|
260
|
+
### useDisconnect
|
|
132
261
|
|
|
133
|
-
|
|
262
|
+
Disconnect from wallet:
|
|
134
263
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
### useSignIn (Solana)
|
|
264
|
+
```tsx
|
|
265
|
+
import { useDisconnect } from "@phantom/react-sdk";
|
|
138
266
|
|
|
139
|
-
|
|
267
|
+
function DisconnectButton() {
|
|
268
|
+
const { disconnect, isLoading } = useDisconnect();
|
|
140
269
|
|
|
141
|
-
|
|
270
|
+
return (
|
|
271
|
+
<button onClick={disconnect} disabled={isLoading}>
|
|
272
|
+
{isLoading ? "Disconnecting..." : "Disconnect"}
|
|
273
|
+
</button>
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
```
|
|
142
277
|
|
|
143
|
-
|
|
278
|
+
### useSignMessage
|
|
144
279
|
|
|
145
|
-
|
|
280
|
+
Sign messages with native string input:
|
|
146
281
|
|
|
147
282
|
```tsx
|
|
148
|
-
import {
|
|
149
|
-
import { SolanaSignInData } from "@phantom/browser-sdk/solana"; // This type might be needed from the browser-sdk
|
|
283
|
+
import { useSignMessage, NetworkId } from "@phantom/react-sdk";
|
|
150
284
|
|
|
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
|
-
};
|
|
285
|
+
function SignMessage() {
|
|
286
|
+
const { signMessage, isLoading, error } = useSignMessage();
|
|
162
287
|
|
|
288
|
+
const handleSign = async () => {
|
|
163
289
|
try {
|
|
164
|
-
const
|
|
165
|
-
console.log("
|
|
166
|
-
// You can now verify the signature and signedMessage on your backend
|
|
167
|
-
// Handle successful sign-in (e.g., update UI, set user session)
|
|
290
|
+
const signature = await signMessage("Hello from Phantom!", NetworkId.SOLANA_MAINNET);
|
|
291
|
+
console.log("Signature:", signature);
|
|
168
292
|
} catch (err) {
|
|
169
|
-
console.error("
|
|
170
|
-
// Handle sign-in error (e.g., show error message to user)
|
|
293
|
+
console.error("Failed to sign:", err);
|
|
171
294
|
}
|
|
172
295
|
};
|
|
173
296
|
|
|
174
|
-
return
|
|
297
|
+
return (
|
|
298
|
+
<button onClick={handleSign} disabled={isLoading}>
|
|
299
|
+
{isLoading ? "Signing..." : "Sign Message"}
|
|
300
|
+
</button>
|
|
301
|
+
);
|
|
175
302
|
}
|
|
176
|
-
|
|
303
|
+
```
|
|
177
304
|
|
|
178
|
-
###
|
|
305
|
+
### useSignAndSendTransaction
|
|
179
306
|
|
|
180
|
-
|
|
307
|
+
#### Solana Transaction
|
|
181
308
|
|
|
182
|
-
|
|
309
|
+
```tsx
|
|
310
|
+
import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
|
|
311
|
+
import { Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
|
|
312
|
+
|
|
313
|
+
function SendSolanaTransaction() {
|
|
314
|
+
const { signAndSendTransaction, isLoading, error } = useSignAndSendTransaction();
|
|
315
|
+
|
|
316
|
+
const handleSend = async () => {
|
|
317
|
+
// Create native Solana transaction - no encoding needed!
|
|
318
|
+
const transaction = new Transaction().add(
|
|
319
|
+
SystemProgram.transfer({
|
|
320
|
+
fromPubkey: new PublicKey(fromAddress),
|
|
321
|
+
toPubkey: new PublicKey(toAddress),
|
|
322
|
+
lamports: 0.001 * LAMPORTS_PER_SOL,
|
|
323
|
+
}),
|
|
324
|
+
);
|
|
183
325
|
|
|
184
|
-
|
|
326
|
+
try {
|
|
327
|
+
const result = await signAndSendTransaction({
|
|
328
|
+
networkId: NetworkId.SOLANA_MAINNET,
|
|
329
|
+
transaction: transaction, // Native Transaction object!
|
|
330
|
+
});
|
|
331
|
+
console.log("Transaction sent:", result.rawTransaction);
|
|
332
|
+
} catch (err) {
|
|
333
|
+
console.error("Failed to send:", err);
|
|
334
|
+
}
|
|
335
|
+
};
|
|
185
336
|
|
|
186
|
-
|
|
337
|
+
return (
|
|
338
|
+
<button onClick={handleSend} disabled={isLoading}>
|
|
339
|
+
{isLoading ? "Sending..." : "Send SOL"}
|
|
340
|
+
</button>
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
#### Ethereum Transaction (with Viem)
|
|
187
346
|
|
|
188
347
|
```tsx
|
|
189
|
-
import {
|
|
348
|
+
import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
|
|
349
|
+
import { parseEther, parseGwei } from "viem";
|
|
190
350
|
|
|
191
|
-
function
|
|
192
|
-
const {
|
|
351
|
+
function SendEthereumTransaction() {
|
|
352
|
+
const { signAndSendTransaction, isLoading } = useSignAndSendTransaction();
|
|
193
353
|
|
|
194
|
-
const
|
|
195
|
-
const messageToSign = "Please confirm your action by signing this message.";
|
|
196
|
-
const messageBytes = new TextEncoder().encode(messageToSign);
|
|
354
|
+
const handleSend = async () => {
|
|
197
355
|
try {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
356
|
+
const result = await signAndSendTransaction({
|
|
357
|
+
networkId: NetworkId.ETHEREUM_MAINNET,
|
|
358
|
+
transaction: {
|
|
359
|
+
to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
|
|
360
|
+
value: parseEther("0.001"), // 0.001 ETH
|
|
361
|
+
gas: 21000n,
|
|
362
|
+
gasPrice: parseGwei("20"), // 20 gwei
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
console.log("Transaction sent:", result);
|
|
203
366
|
} catch (err) {
|
|
204
|
-
console.error("
|
|
205
|
-
// Handle error (e.g., user rejected, wallet error)
|
|
367
|
+
console.error("Failed to send:", err);
|
|
206
368
|
}
|
|
207
369
|
};
|
|
208
370
|
|
|
209
|
-
return
|
|
371
|
+
return (
|
|
372
|
+
<button onClick={handleSend} disabled={isLoading}>
|
|
373
|
+
{isLoading ? "Sending..." : "Send ETH"}
|
|
374
|
+
</button>
|
|
375
|
+
);
|
|
210
376
|
}
|
|
211
377
|
```
|
|
212
378
|
|
|
213
|
-
|
|
379
|
+
## Network Support
|
|
380
|
+
|
|
381
|
+
### Supported Networks
|
|
214
382
|
|
|
215
|
-
The
|
|
383
|
+
The SDK automatically determines the transaction type from the NetworkId:
|
|
216
384
|
|
|
217
|
-
####
|
|
385
|
+
#### Solana
|
|
218
386
|
|
|
219
|
-
|
|
387
|
+
- `NetworkId.SOLANA_MAINNET`
|
|
388
|
+
- `NetworkId.SOLANA_DEVNET`
|
|
389
|
+
- `NetworkId.SOLANA_TESTNET`
|
|
390
|
+
|
|
391
|
+
#### Ethereum/EVM
|
|
392
|
+
|
|
393
|
+
- `NetworkId.ETHEREUM_MAINNET`
|
|
394
|
+
- `NetworkId.ETHEREUM_SEPOLIA`
|
|
395
|
+
- `NetworkId.POLYGON_MAINNET`
|
|
396
|
+
- `NetworkId.ARBITRUM_ONE`
|
|
397
|
+
- `NetworkId.OPTIMISM_MAINNET`
|
|
398
|
+
- `NetworkId.BASE_MAINNET`
|
|
399
|
+
|
|
400
|
+
#### Bitcoin
|
|
401
|
+
|
|
402
|
+
- `NetworkId.BITCOIN_MAINNET`
|
|
403
|
+
- `NetworkId.BITCOIN_TESTNET`
|
|
404
|
+
|
|
405
|
+
#### Sui
|
|
406
|
+
|
|
407
|
+
- `NetworkId.SUI_MAINNET`
|
|
408
|
+
- `NetworkId.SUI_TESTNET`
|
|
409
|
+
- `NetworkId.SUI_DEVNET`
|
|
410
|
+
|
|
411
|
+
### Provider Network Support
|
|
412
|
+
|
|
413
|
+
| Provider Type | Network Support |
|
|
414
|
+
| ------------- | ----------------------------------------------- |
|
|
415
|
+
| **Injected** | All networks supported by Phantom extension |
|
|
416
|
+
| **Embedded** | All networks based on configured `addressTypes` |
|
|
417
|
+
|
|
418
|
+
## Transaction Examples
|
|
419
|
+
|
|
420
|
+
### Solana with @solana/web3.js
|
|
421
|
+
|
|
422
|
+
```tsx
|
|
423
|
+
import { Transaction, SystemProgram, PublicKey } from "@solana/web3.js";
|
|
424
|
+
import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
|
|
425
|
+
|
|
426
|
+
function SolanaExample() {
|
|
427
|
+
const { signAndSendTransaction } = useSignAndSendTransaction();
|
|
428
|
+
|
|
429
|
+
const sendTransaction = async () => {
|
|
430
|
+
const transaction = new Transaction().add(
|
|
431
|
+
SystemProgram.transfer({
|
|
432
|
+
fromPubkey: new PublicKey(fromAddress),
|
|
433
|
+
toPubkey: new PublicKey(toAddress),
|
|
434
|
+
lamports: 1000000, // 0.001 SOL
|
|
435
|
+
}),
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
// No serialization or encoding needed!
|
|
439
|
+
const result = await signAndSendTransaction({
|
|
440
|
+
networkId: NetworkId.SOLANA_MAINNET,
|
|
441
|
+
transaction,
|
|
442
|
+
});
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
```
|
|
220
446
|
|
|
221
|
-
|
|
447
|
+
### Solana with @solana/kit
|
|
222
448
|
|
|
223
449
|
```tsx
|
|
224
|
-
import { useSignAndSendTransaction } from "@phantom/react-sdk/solana"; // scoped import is fine
|
|
225
450
|
import {
|
|
226
451
|
createSolanaRpc,
|
|
452
|
+
pipe,
|
|
227
453
|
createTransactionMessage,
|
|
228
454
|
setTransactionMessageFeePayer,
|
|
229
455
|
setTransactionMessageLifetimeUsingBlockhash,
|
|
230
|
-
pipe,
|
|
231
456
|
address,
|
|
232
457
|
compileTransaction,
|
|
233
458
|
} from "@solana/kit";
|
|
459
|
+
import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
|
|
234
460
|
|
|
235
|
-
function
|
|
461
|
+
function SolanaKitExample() {
|
|
236
462
|
const { signAndSendTransaction } = useSignAndSendTransaction();
|
|
237
463
|
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
464
|
+
const sendTransaction = async () => {
|
|
465
|
+
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
|
|
466
|
+
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
241
467
|
|
|
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
|
-
};
|
|
468
|
+
const transactionMessage = pipe(
|
|
469
|
+
createTransactionMessage({ version: 0 }),
|
|
470
|
+
tx => setTransactionMessageFeePayer(address(userPublicKey), tx),
|
|
471
|
+
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
|
|
472
|
+
);
|
|
263
473
|
|
|
264
|
-
|
|
474
|
+
const transaction = compileTransaction(transactionMessage);
|
|
475
|
+
|
|
476
|
+
const result = await signAndSendTransaction({
|
|
477
|
+
networkId: NetworkId.SOLANA_MAINNET,
|
|
478
|
+
transaction,
|
|
479
|
+
});
|
|
480
|
+
};
|
|
265
481
|
}
|
|
266
482
|
```
|
|
267
483
|
|
|
268
|
-
###
|
|
484
|
+
### Ethereum with Viem
|
|
269
485
|
|
|
270
|
-
|
|
486
|
+
```tsx
|
|
487
|
+
import { parseEther, parseGwei, encodeFunctionData } from "viem";
|
|
488
|
+
import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
|
|
271
489
|
|
|
272
|
-
|
|
490
|
+
function EthereumExample() {
|
|
491
|
+
const { signAndSendTransaction } = useSignAndSendTransaction();
|
|
273
492
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
|
|
493
|
+
const sendEth = async () => {
|
|
494
|
+
const result = await signAndSendTransaction({
|
|
495
|
+
networkId: NetworkId.ETHEREUM_MAINNET,
|
|
496
|
+
transaction: {
|
|
497
|
+
to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
|
|
498
|
+
value: parseEther("1"), // 1 ETH
|
|
499
|
+
gas: 21000n,
|
|
500
|
+
gasPrice: parseGwei("20"), // 20 gwei
|
|
501
|
+
},
|
|
502
|
+
});
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
const sendToken = async () => {
|
|
506
|
+
const result = await signAndSendTransaction({
|
|
507
|
+
networkId: NetworkId.ETHEREUM_MAINNET,
|
|
508
|
+
transaction: {
|
|
509
|
+
to: tokenContractAddress,
|
|
510
|
+
data: encodeFunctionData({
|
|
511
|
+
abi: erc20Abi,
|
|
512
|
+
functionName: "transfer",
|
|
513
|
+
args: [recipientAddress, parseEther("100")],
|
|
514
|
+
}),
|
|
515
|
+
gas: 50000n,
|
|
516
|
+
maxFeePerGas: parseGwei("30"),
|
|
517
|
+
maxPriorityFeePerGas: parseGwei("2"),
|
|
518
|
+
},
|
|
519
|
+
});
|
|
520
|
+
};
|
|
521
|
+
}
|
|
286
522
|
```
|
|
287
523
|
|
|
288
|
-
##
|
|
524
|
+
## Advanced Usage
|
|
525
|
+
|
|
526
|
+
### Multi-Chain Application
|
|
289
527
|
|
|
290
|
-
|
|
528
|
+
```tsx
|
|
529
|
+
import { useSignAndSendTransaction, NetworkId } from "@phantom/react-sdk";
|
|
530
|
+
import { Transaction, SystemProgram, PublicKey } from "@solana/web3.js";
|
|
531
|
+
import { parseEther } from "viem";
|
|
532
|
+
|
|
533
|
+
function MultiChainWallet() {
|
|
534
|
+
const { signAndSendTransaction } = useSignAndSendTransaction();
|
|
535
|
+
|
|
536
|
+
const sendSolana = async () => {
|
|
537
|
+
const transaction = new Transaction().add(
|
|
538
|
+
SystemProgram.transfer({
|
|
539
|
+
fromPubkey: new PublicKey(solanaAddress),
|
|
540
|
+
toPubkey: new PublicKey(recipient),
|
|
541
|
+
lamports: 1000000,
|
|
542
|
+
}),
|
|
543
|
+
);
|
|
544
|
+
|
|
545
|
+
return await signAndSendTransaction({
|
|
546
|
+
networkId: NetworkId.SOLANA_MAINNET,
|
|
547
|
+
transaction,
|
|
548
|
+
});
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
const sendEthereum = async () => {
|
|
552
|
+
return await signAndSendTransaction({
|
|
553
|
+
networkId: NetworkId.ETHEREUM_MAINNET,
|
|
554
|
+
transaction: {
|
|
555
|
+
to: recipient,
|
|
556
|
+
value: parseEther("0.1"),
|
|
557
|
+
gas: 21000n,
|
|
558
|
+
},
|
|
559
|
+
});
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
return (
|
|
563
|
+
<div>
|
|
564
|
+
<button onClick={sendSolana}>Send SOL</button>
|
|
565
|
+
<button onClick={sendEthereum}>Send ETH</button>
|
|
566
|
+
</div>
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Hooks Reference
|
|
572
|
+
|
|
573
|
+
Quick reference of all available hooks:
|
|
574
|
+
|
|
575
|
+
| Hook | Purpose | Returns |
|
|
576
|
+
|------|---------|---------|
|
|
577
|
+
| `useConnect` | Connect to wallet | `{ connect, isConnecting, error }` |
|
|
578
|
+
| `useAccounts` | Get wallet addresses | `WalletAddress[]` or `null` |
|
|
579
|
+
| `useIsExtensionInstalled` | Check extension status | `{ isLoading, isInstalled }` |
|
|
580
|
+
| `useDisconnect` | Disconnect from wallet | `{ disconnect, isDisconnecting }` |
|
|
581
|
+
| `useSignMessage` | Sign text messages | `{ signMessage, isSigning, error }` |
|
|
582
|
+
| `useSignAndSendTransaction` | Sign and send transactions | `{ signAndSendTransaction, isSigning, error }` |
|
|
583
|
+
| `useCreateUserOrganization` | Create user organization (embedded) | `{ createUserOrganization, isCreating, error }` |
|
|
584
|
+
| `usePhantom` | Get provider context | `{ isConnected, isReady, currentProviderType }` |
|
|
585
|
+
|
|
586
|
+
## Configuration Reference
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
interface PhantomSDKConfig {
|
|
590
|
+
providerType: "injected" | "embedded";
|
|
591
|
+
|
|
592
|
+
// Required for embedded provider only
|
|
593
|
+
addressTypes?: AddressType[]; // Networks to enable
|
|
594
|
+
apiBaseUrl?: string; // Phantom API base URL
|
|
595
|
+
organizationId?: string; // Your organization ID
|
|
596
|
+
authUrl?: string; // Custom auth URL (optional)
|
|
597
|
+
embeddedWalletType?: "app-wallet" | "user-wallet"; // Wallet type
|
|
598
|
+
solanaProvider?: "web3js" | "kit"; // Solana library choice (default: 'web3js')
|
|
599
|
+
}
|
|
600
|
+
```
|
|
291
601
|
|
|
292
|
-
|
|
602
|
+
For more details, examples, and bundle optimization tips, see the [@phantom/browser-sdk documentation](../browser-sdk/README.md).
|