@phantom/browser-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,142 +1,304 @@
1
- # Phantom Browser SDK
1
+ # @phantom/browser-sdk
2
2
 
3
- The Phantom Browser SDK allows you to interact with the Phantom wallet from your web application. It uses a plugin system to support different blockchains.
3
+ Browser SDK for Phantom Wallet supporting both injected and embedded non-custodial wallets.
4
4
 
5
- ## Installation
6
-
7
- You can install the SDK using npm or yarn:
8
-
9
- **npm:**
5
+ ## Quick Start
10
6
 
11
7
  ```bash
12
8
  npm install @phantom/browser-sdk
13
9
  ```
14
10
 
15
- **yarn:**
11
+ ### Injected Provider (Browser Extension)
16
12
 
17
- ```bash
18
- yarn add @phantom/browser-sdk
13
+ ```typescript
14
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
15
+
16
+ // Connect to Phantom browser extension
17
+ const sdk = new BrowserSDK({
18
+ providerType: "injected",
19
+ });
20
+
21
+ const { addresses } = await sdk.connect();
22
+ console.log("Connected addresses:", addresses);
23
+
24
+ // Sign and send transactions
25
+ const result = await sdk.signAndSendTransaction({
26
+ networkId: NetworkId.SOLANA_MAINNET,
27
+ transaction: mySolanaTransaction,
28
+ });
19
29
  ```
20
30
 
21
- ## Usage
31
+ ### Embedded Provider
32
+
33
+ ```typescript
34
+ import { BrowserSDK, AddressType, NetworkId } from "@phantom/browser-sdk";
35
+
36
+ // Create embedded non-custodial wallet
37
+ const sdk = new BrowserSDK({
38
+ providerType: "embedded",
39
+ addressTypes: [AddressType.solana, AddressType.ethereum],
40
+ apiBaseUrl: "https://api.phantom.com",
41
+ organizationId: "your-org-id",
42
+ });
22
43
 
23
- Here's an example of how to import and use the SDK with the Solana plugin:
44
+ const { walletId, addresses } = await sdk.connect();
45
+ console.log("Wallet ID:", walletId);
46
+ console.log("Addresses:", addresses);
47
+
48
+ const result = await sdk.signAndSendTransaction({
49
+ networkId: NetworkId.SOLANA_MAINNET,
50
+ transaction: mySolanaTransaction,
51
+ });
52
+ ```
53
+
54
+ ## Features
55
+
56
+ - **🔒 Non-Custodial**: Full user control of private keys for both injected and embedded wallets
57
+ - **🌐 Dual Provider Support**: Works with Phantom browser extension or creates embedded wallets
58
+ - **🛠️ Native Transactions**: Work with blockchain-native objects, not base64url strings
59
+ - **🔗 Multi-Chain**: Solana, Ethereum, Bitcoin, Sui support
60
+ - **⚡ TypeScript**: Full type safety for all transaction formats
61
+ - **🎯 Unified API**: Same interface for both injected and embedded providers
62
+
63
+ ## Provider Types
64
+
65
+ ### Injected Provider
66
+
67
+ Uses the Phantom browser extension installed by the user. No additional configuration needed.
24
68
 
25
69
  ```typescript
26
- import { createPhantom } from "@phantom/browser-sdk";
27
- import { createSolanaPlugin } from "@phantom/browser-sdk/solana"; // Import the solana plugin
70
+ const sdk = new BrowserSDK({
71
+ providerType: "injected",
72
+ });
73
+ ```
74
+
75
+ ### Embedded Provider
28
76
 
29
- // Create a Phantom instance with the Solana plugin
30
- const phantom = createPhantom({
31
- plugins: [createSolanaPlugin()],
77
+ Creates a non-custodial wallet embedded in your application. Requires API configuration.
78
+
79
+ ```typescript
80
+ const sdk = new BrowserSDK({
81
+ providerType: "embedded",
82
+ addressTypes: [AddressType.solana, AddressType.ethereum],
83
+ apiBaseUrl: "https://api.phantom.com",
84
+ organizationId: "your-org-id",
85
+ embeddedWalletType: "app-wallet", // or 'user-wallet'
32
86
  });
87
+ ```
33
88
 
34
- // Now you can use the Solana-specific methods
35
- async function connectAndSign() {
36
- try {
37
- // Attempt to connect to the wallet
38
- const connectionResult = await phantom.solana.connect();
39
- console.log("Connection Result:", connectionResult.address);
40
-
41
- // Example: Sign in (if supported by the specific provider/plugin)
42
- // Construct SolanaSignInData according to your needs
43
- const signInData = { domain: window.location.host, statement: "Please sign in to access this dApp." };
44
- const signInResult = await phantom.solana.signIn(signInData);
45
- console.log("Sign In Result:", signInResult.address);
46
-
47
- // Example: Sign a message
48
- const message = new TextEncoder().encode("Hello from Phantom Browser SDK!");
49
- const signedMessage = await phantom.solana.signMessage(message, "utf8");
50
- console.log("Signed Message:", signedMessage);
51
- } catch (error) {
52
- console.error("Error interacting with Phantom:", error);
53
- }
89
+ ### Embedded Wallet Types
90
+
91
+ #### App Wallet (`'app-wallet'`)
92
+
93
+ - **New wallets** created per application
94
+ - **Unfunded** by default - you need to fund them
95
+ - **Independent** from user's existing Phantom wallet
96
+ - **Perfect for**: Gaming, DeFi protocols, or apps that need fresh wallets
97
+
98
+ ```typescript
99
+ const sdk = new BrowserSDK({
100
+ providerType: "embedded",
101
+ embeddedWalletType: "app-wallet",
102
+ addressTypes: [AddressType.solana],
103
+ // ... other config
104
+ });
105
+ ```
106
+
107
+ #### User Wallet (`'user-wallet'`)
108
+
109
+ - **Uses Phantom authentication** - user logs in with existing Phantom account
110
+ - **Potentially funded** - brings in user's existing wallet balance
111
+ - **Connected** to user's Phantom ecosystem
112
+ - **Perfect for**: Trading platforms, NFT marketplaces, or apps needing funded wallets
113
+
114
+ ```typescript
115
+ const sdk = new BrowserSDK({
116
+ providerType: "embedded",
117
+ embeddedWalletType: "user-wallet",
118
+ addressTypes: [AddressType.solana, AddressType.ethereum],
119
+ // ... other config
120
+ });
121
+ ```
122
+
123
+ ### Available AddressTypes (Embedded Only)
124
+
125
+ | AddressType | Networks Supported |
126
+ | --------------------------- | ------------------------------------------- |
127
+ | `AddressType.solana` | Solana Mainnet, Devnet, Testnet |
128
+ | `AddressType.ethereum` | Ethereum, Polygon, Arbitrum, Optimism, Base |
129
+ | `AddressType.bitcoinSegwit` | Bitcoin Mainnet, Testnet |
130
+ | `AddressType.sui` | Sui Mainnet, Testnet, Devnet |
131
+
132
+ ### Solana Provider Configuration
133
+
134
+ When using `AddressType.solana`, you can choose between two Solana libraries:
135
+
136
+ ```typescript
137
+ const sdk = new BrowserSDK({
138
+ providerType: "embedded",
139
+ addressTypes: [AddressType.solana],
140
+ solanaProvider: "web3js", // or 'kit'
141
+ // ... other config
142
+ });
143
+ ```
144
+
145
+ **Provider Options:**
146
+
147
+ - `'web3js'` (default) - Uses `@solana/web3.js` library
148
+ - `'kit'` - Uses `@solana/kit` library (modern, TypeScript-first)
149
+
150
+ **When to use each:**
151
+
152
+ - **@solana/web3.js**: Better ecosystem compatibility, wider community support
153
+ - **@solana/kit**: Better TypeScript support, modern architecture, smaller bundle size
154
+
155
+ ## API Reference
156
+
157
+ ### Constructor
158
+
159
+ ```typescript
160
+ new BrowserSDK(config: BrowserSDKConfig)
161
+ ```
162
+
163
+ #### BrowserSDKConfig
164
+
165
+ ```typescript
166
+ interface BrowserSDKConfig {
167
+ providerType: "injected" | "embedded";
168
+
169
+ // Required for embedded provider only
170
+ addressTypes?: AddressType[]; // Networks to enable
171
+ apiBaseUrl?: string; // Phantom API base URL
172
+ organizationId?: string; // Your organization ID
173
+ authUrl?: string; // Custom auth URL (optional)
174
+ embeddedWalletType?: "app-wallet" | "user-wallet"; // Wallet type
175
+ solanaProvider?: "web3js" | "kit"; // Solana library choice (default: 'web3js')
54
176
  }
177
+ ```
178
+
179
+ ### Methods
180
+
181
+ #### connect()
182
+
183
+ Connect to wallet and get addresses for configured AddressTypes.
184
+
185
+ ```typescript
186
+ const result = await sdk.connect();
187
+ // Returns: { walletId: string, addresses: WalletAddress[] }
188
+ // addresses only includes types from addressTypes config
189
+ ```
190
+
191
+ #### signAndSendTransaction(transaction)
192
+
193
+ Sign and send a native transaction object.
194
+
195
+ ```typescript
196
+ // Solana transaction
197
+ const result = await sdk.signAndSendTransaction({
198
+ networkId: NetworkId.SOLANA_MAINNET,
199
+ transaction: solanaTransaction, // Native Transaction or VersionedTransaction
200
+ });
55
201
 
56
- connectAndSign();
202
+ // Ethereum transaction
203
+ const result = await sdk.signAndSendTransaction({
204
+ networkId: NetworkId.ETHEREUM_MAINNET,
205
+ transaction: {
206
+ to: "0x...",
207
+ value: parseEther("1"), // 1 ETH
208
+ gas: 21000n,
209
+ },
210
+ });
57
211
  ```
58
212
 
59
- ### Available Solana Methods
213
+ #### signMessage(params)
214
+
215
+ Sign a message string.
60
216
 
61
- Once the `phantom.solana` object is initialized, you can access the following methods:
217
+ ```typescript
218
+ const signature = await sdk.signMessage({
219
+ message: "Hello from Phantom!",
220
+ networkId: NetworkId.SOLANA_MAINNET,
221
+ });
222
+ ```
62
223
 
63
- - `connect(opts?: { onlyIfTrusted?: boolean }): Promise<string>`
64
- - Connects to the Phantom wallet. Optionally, `onlyIfTrusted` can be set to true to only connect if the dApp is already trusted.
65
- - `disconnect(): Promise<void>`
66
- - Disconnects from the Phantom wallet.
67
- - `getAccount(): Promise<string | undefined>`
68
- - Gets the current connected address
69
- - `signIn(): Promise<SignInResult>`
70
- - Initiates a sign-in request to the wallet.
71
- - `signMessage(message: Uint8Array | string, display?: 'utf8' | 'hex'): Promise<SignedMessage>`
72
- - Prompts the user to sign a given message.
73
- - `signAndSendTransaction(transaction: Transaction): Promise<{ signature: string; address?: string }>`
74
- - Prompts the user to sign **and send** a Kit `Transaction` and returns the confirmed signature.
224
+ **Parameters:**
75
225
 
76
- ### Available Extension Methods
226
+ - `params.message` (string) - Message to sign
227
+ - `params.networkId` (NetworkId) - Network identifier
77
228
 
78
- Once the `phantom.extension` object is initialized, you can access the following methods:
229
+ #### getAddresses()
79
230
 
80
- - `isInstalled(): boolean`
81
- - Displays `true` if the phantom extension is installed, `false` if not
231
+ Get connected wallet addresses.
82
232
 
83
- ### Event Handling
233
+ ```typescript
234
+ const addresses = await sdk.getAddresses();
235
+ // Returns addresses matching configured AddressTypes
236
+ ```
84
237
 
85
- The SDK also allows you to listen for `connect`, `disconnect`, and `accountChanged` events:
238
+ #### disconnect()
86
239
 
87
- - `addEventListener(event: PhantomEventType, callback: PhantomEventCallback): () => void`
240
+ Disconnect from wallet and clear session.
88
241
 
89
- - Registers a callback that will be invoked when the specified event occurs.
90
- - For the `connect` event, the callback receives the public key (as a string) of the connected account.
91
- - For the `disconnect` event, the callback receives no arguments.
92
- - For the `accountChanged` event, the callback receives the new public key (as a string).
93
- - Returns a function that, when called, will unregister the callback.
94
- - Multiple callbacks can be registered for the same event.
242
+ ```typescript
243
+ await sdk.disconnect();
244
+ ```
95
245
 
96
- **Example:**
246
+ ## Transaction Examples
97
247
 
98
- ```typescript
99
- const phantom = createPhantom({ plugins: [createSolanaPlugin()] });
248
+ ### Solana Transactions
100
249
 
101
- const handleConnect = (address: string) => {
102
- console.log(`Wallet connected with public key: ${address}`);
103
- };
250
+ The SDK supports two different Solana transaction libraries. Choose based on your needs:
104
251
 
105
- const clearConnectListener = phantom.solana.addEventListener("connect", handleConnect);
252
+ #### Option 1: @solana/web3.js (Legacy Library)
106
253
 
107
- const handleAccountChanged = (newAddress: string) => {
108
- console.log(`Account changed to: ${newAddress}`);
109
- };
254
+ Traditional Solana library with broader ecosystem support.
110
255
 
111
- const clearAccountChangedListener = phantom.solana.addEventListener("accountChanged", handleAccountChanged);
256
+ ```bash
257
+ npm install @solana/web3.js
258
+ ```
112
259
 
113
- // To stop listening for a specific event:
114
- // clearConnectListener();
115
- // clearAccountChangedListener();
116
- ```
260
+ ```typescript
261
+ import { Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
262
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
263
+
264
+ // Create native Solana transaction
265
+ const transaction = new Transaction().add(
266
+ SystemProgram.transfer({
267
+ fromPubkey: new PublicKey(fromAddress),
268
+ toPubkey: new PublicKey(toAddress),
269
+ lamports: 0.001 * LAMPORTS_PER_SOL,
270
+ }),
271
+ );
117
272
 
118
- - `removeEventListener(event: PhantomEventType, callback: PhantomEventCallback): void`
273
+ // Send native transaction object - no encoding needed!
274
+ const result = await sdk.signAndSendTransaction({
275
+ networkId: NetworkId.SOLANA_MAINNET,
276
+ transaction: transaction,
277
+ });
119
278
 
120
- - Unregisters a previously registered callback for the specified event.
279
+ console.log("Transaction signature:", result.rawTransaction);
280
+ ```
121
281
 
122
- **Example:**
282
+ **VersionedTransaction with @solana/web3.js:**
123
283
 
124
- ```typescript
125
- const phantom = createPhantom({ plugins: [createSolanaPlugin()] });
284
+ ```typescript
285
+ import { VersionedTransaction } from "@solana/web3.js";
126
286
 
127
- const handleDisconnect = () => {
128
- console.log("Wallet disconnected");
129
- };
287
+ const versionedTx = new VersionedTransaction(message);
130
288
 
131
- phantom.solana.addEventListener("disconnect", handleDisconnect);
289
+ const result = await sdk.signAndSendTransaction({
290
+ networkId: NetworkId.SOLANA_DEVNET,
291
+ transaction: versionedTx,
292
+ });
293
+ ```
132
294
 
133
- // To stop listening for this specific disconnect event:
134
- // phantom.solana.removeEventListener("disconnect", handleDisconnect);
135
- ```
295
+ #### Option 2: @solana/kit (Modern Library)
136
296
 
137
- ### Creating a transaction
297
+ New high-performance Solana library with better TypeScript support.
138
298
 
139
- Phantom's SDK uses the `@solana/kit` library to create transactions. You can use the `createTransactionMessage` function to create a transaction message.
299
+ ```bash
300
+ npm install @solana/kit
301
+ ```
140
302
 
141
303
  ```typescript
142
304
  import {
@@ -148,20 +310,406 @@ import {
148
310
  address,
149
311
  compileTransaction,
150
312
  } from "@solana/kit";
313
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
151
314
 
152
- // Example: Sign and send a transaction
153
-
154
- const rpc = createSolanaRpc("https://my-rpc-url.com"); // Replace with your own RPC URL
155
-
315
+ // Create transaction with @solana/kit
316
+ const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
156
317
  const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
157
318
 
158
319
  const transactionMessage = pipe(
159
320
  createTransactionMessage({ version: 0 }),
160
- tx => setTransactionMessageFeePayer(address(userPublicKey as string), tx),
321
+ tx => setTransactionMessageFeePayer(address(userPublicKey), tx),
161
322
  tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
162
323
  );
163
324
 
164
325
  const transaction = compileTransaction(transactionMessage);
165
326
 
166
- const { signature } = await phantomInstance.solana.signAndSendTransaction(transaction);
327
+ const result = await sdk.signAndSendTransaction({
328
+ networkId: NetworkId.SOLANA_MAINNET,
329
+ transaction: transaction,
330
+ });
331
+ ```
332
+
333
+ ### Ethereum Transactions (with Viem)
334
+
335
+ ```typescript
336
+ import { parseEther, parseGwei, encodeFunctionData } from "viem";
337
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
338
+
339
+ // Simple ETH transfer
340
+ const result = await sdk.signAndSendTransaction({
341
+ networkId: NetworkId.ETHEREUM_MAINNET,
342
+ transaction: {
343
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
344
+ value: parseEther("1"), // 1 ETH
345
+ gas: 21000n,
346
+ gasPrice: parseGwei("20"), // 20 gwei
347
+ },
348
+ });
349
+
350
+ // EIP-1559 transaction with maxFeePerGas
351
+ const result = await sdk.signAndSendTransaction({
352
+ networkId: NetworkId.ETHEREUM_MAINNET,
353
+ transaction: {
354
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
355
+ value: parseEther("1"),
356
+ data: encodeFunctionData({
357
+ abi: tokenAbi,
358
+ functionName: "transfer",
359
+ args: ["0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E", parseEther("1")],
360
+ }),
361
+ gas: 50000n,
362
+ maxFeePerGas: parseGwei("30"), // 30 gwei
363
+ maxPriorityFeePerGas: parseGwei("2"), // 2 gwei
364
+ type: "eip1559",
365
+ },
366
+ });
367
+ ```
368
+
369
+ #### Other EVM Networks
370
+
371
+ ```typescript
372
+ // Polygon transaction
373
+ const result = await sdk.signAndSendTransaction({
374
+ networkId: NetworkId.POLYGON_MAINNET,
375
+ transaction: {
376
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
377
+ value: parseEther("1"), // 1 MATIC
378
+ gas: 21000n,
379
+ },
380
+ });
381
+
382
+ // Arbitrum transaction
383
+ const result = await sdk.signAndSendTransaction({
384
+ networkId: NetworkId.ARBITRUM_ONE,
385
+ transaction: {
386
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
387
+ value: parseEther("0.1"), // 0.1 ETH
388
+ gas: 21000n,
389
+ },
390
+ });
391
+ ```
392
+
393
+ ### Bitcoin Transactions
394
+
395
+ ```typescript
396
+ // Bitcoin transaction
397
+ const result = await sdk.signAndSendTransaction({
398
+ networkId: NetworkId.BITCOIN_MAINNET,
399
+ transaction: {
400
+ inputs: [
401
+ {
402
+ txid: "previous-transaction-id",
403
+ vout: 0,
404
+ scriptSig: "...",
405
+ },
406
+ ],
407
+ outputs: [
408
+ {
409
+ value: 50000, // satoshis
410
+ scriptPubKey: "76a914...88ac", // P2PKH script
411
+ },
412
+ ],
413
+ version: 2,
414
+ locktime: 0,
415
+ },
416
+ });
417
+
418
+ // Bitcoin testnet
419
+ const result = await sdk.signAndSendTransaction({
420
+ networkId: NetworkId.BITCOIN_TESTNET,
421
+ transaction: {
422
+ // ... transaction details
423
+ },
424
+ });
425
+ ```
426
+
427
+ ### Sui Transactions
428
+
429
+ ```typescript
430
+ import { TransactionBlock } from "@mysten/sui.js/transactions";
431
+
432
+ // Create Sui transaction block
433
+ const txb = new TransactionBlock();
434
+ txb.transferObjects([coin], recipientAddress);
435
+
436
+ const result = await sdk.signAndSendTransaction({
437
+ networkId: NetworkId.SUI_MAINNET,
438
+ transaction: {
439
+ kind: "moveCall", // or 'transferObject', 'transferSui', 'pay'
440
+ data: txb, // TransactionBlock from @mysten/sui.js
441
+ },
442
+ });
443
+
444
+ // Sui testnet
445
+ const result = await sdk.signAndSendTransaction({
446
+ networkId: NetworkId.SUI_TESTNET,
447
+ transaction: {
448
+ kind: "transferSui",
449
+ data: suiTransactionData,
450
+ },
451
+ });
452
+ ```
453
+
454
+ ## Network IDs Reference
455
+
456
+ Use the exported `NetworkId` enum for type safety:
457
+
458
+ ```typescript
459
+ import { NetworkId } from "@phantom/browser-sdk";
460
+ ```
461
+
462
+ ### Solana
463
+
464
+ - `NetworkId.SOLANA_MAINNET` - Solana Mainnet Beta
465
+ - `NetworkId.SOLANA_DEVNET` - Solana Devnet
466
+ - `NetworkId.SOLANA_TESTNET` - Solana Testnet
467
+
468
+ ### Ethereum/EVM
469
+
470
+ - `NetworkId.ETHEREUM_MAINNET` - Ethereum Mainnet
471
+ - `NetworkId.ETHEREUM_SEPOLIA` - Ethereum Sepolia Testnet
472
+ - `NetworkId.POLYGON_MAINNET` - Polygon Mainnet
473
+ - `NetworkId.ARBITRUM_ONE` - Arbitrum One
474
+ - `NetworkId.OPTIMISM_MAINNET` - Optimism Mainnet
475
+ - `NetworkId.BASE_MAINNET` - Base Mainnet
476
+
477
+ ### Bitcoin
478
+
479
+ - `NetworkId.BITCOIN_MAINNET` - Bitcoin Mainnet
480
+ - `NetworkId.BITCOIN_TESTNET` - Bitcoin Testnet
481
+
482
+ ### Sui
483
+
484
+ - `NetworkId.SUI_MAINNET` - Sui Mainnet
485
+ - `NetworkId.SUI_TESTNET` - Sui Testnet
486
+ - `NetworkId.SUI_DEVNET` - Sui Devnet
487
+
488
+ ## Advanced Usage
489
+
490
+ ### Multi-Chain Application
491
+
492
+ ```typescript
493
+ import { BrowserSDK, AddressType } from "@phantom/browser-sdk";
494
+
495
+ const sdk = new BrowserSDK({
496
+ addressTypes: [AddressType.solana, AddressType.ethereum, AddressType.sui],
497
+ apiBaseUrl: "https://api.phantom.com",
498
+ organizationId: "your-org-id",
499
+ });
500
+
501
+ class MultiChainWallet {
502
+ async sendSolana(amount: number, recipient: string) {
503
+ const transaction = new Transaction().add(
504
+ SystemProgram.transfer({
505
+ fromPubkey: new PublicKey(this.solanaAddress),
506
+ toPubkey: new PublicKey(recipient),
507
+ lamports: amount * LAMPORTS_PER_SOL,
508
+ }),
509
+ );
510
+
511
+ return await sdk.signAndSendTransaction({
512
+ networkId: NetworkId.SOLANA_MAINNET,
513
+ transaction,
514
+ });
515
+ }
516
+
517
+ async sendEthereum(amount: string, recipient: string) {
518
+ return await sdk.signAndSendTransaction({
519
+ networkId: NetworkId.ETHEREUM_MAINNET,
520
+ transaction: {
521
+ to: recipient,
522
+ value: parseEther(amount),
523
+ gas: 21000n,
524
+ },
525
+ });
526
+ }
527
+
528
+ async sendSui(coinId: string, recipient: string) {
529
+ const txb = new TransactionBlock();
530
+ txb.transferObjects([coinId], recipient);
531
+
532
+ return await sdk.signAndSendTransaction({
533
+ networkId: NetworkId.SUI_MAINNET,
534
+ transaction: {
535
+ kind: "transferObject",
536
+ data: txb,
537
+ },
538
+ });
539
+ }
540
+ }
541
+ ```
542
+
543
+ ### Error Handling
544
+
545
+ ```typescript
546
+ try {
547
+ const result = await sdk.signAndSendTransaction({
548
+ networkId: NetworkId.SOLANA_MAINNET,
549
+ transaction: myTransaction,
550
+ });
551
+ console.log("Success:", result);
552
+ } catch (error) {
553
+ if (error.message.includes("User rejected")) {
554
+ console.log("User cancelled the transaction");
555
+ } else if (error.message.includes("insufficient funds")) {
556
+ console.log("Not enough balance");
557
+ } else {
558
+ console.error("Transaction failed:", error);
559
+ }
560
+ }
561
+ ```
562
+
563
+ ### Bundle Optimization Tips
564
+
565
+ 1. **Only include networks you need**:
566
+
567
+ ```typescript
568
+ // Good: Only Solana (~250KB)
569
+ addressTypes: [AddressType.solana];
570
+
571
+ // Avoid: All networks if not needed (~800KB+)
572
+ addressTypes: [AddressType.solana, AddressType.ethereum, AddressType.sui, AddressType.bitcoinSegwit];
573
+ ```
574
+
575
+ 2. **Install dependencies based on enabled networks**:
576
+
577
+ | AddressType | Required Dependencies | Bundle Size |
578
+ | --------------------------- | ---------------------------------- | ----------- |
579
+ | `AddressType.solana` | `@solana/web3.js` OR `@solana/kit` | ~250KB |
580
+ | `AddressType.ethereum` | `viem` | ~300KB |
581
+ | `AddressType.bitcoinSegwit` | `bitcoinjs-lib` | ~200KB |
582
+ | `AddressType.sui` | `@mysten/sui.js` | ~250KB |
583
+
584
+ **Example package.json for Solana + Ethereum (using @solana/web3.js)**:
585
+
586
+ ```json
587
+ {
588
+ "dependencies": {
589
+ "@phantom/browser-sdk": "^1.0.0",
590
+ "@solana/web3.js": "^1.87.0",
591
+ "viem": "^2.0.0"
592
+ }
593
+ }
594
+ ```
595
+
596
+ **Example package.json for Solana + Ethereum (using @solana/kit)**:
597
+
598
+ ```json
599
+ {
600
+ "dependencies": {
601
+ "@phantom/browser-sdk": "^1.0.0",
602
+ "@solana/kit": "^2.0.0",
603
+ "viem": "^2.0.0"
604
+ }
605
+ }
606
+ ```
607
+
608
+ **Example package.json for Solana only (using @solana/web3.js)**:
609
+
610
+ ```json
611
+ {
612
+ "dependencies": {
613
+ "@phantom/browser-sdk": "^1.0.0",
614
+ "@solana/web3.js": "^1.87.0"
615
+ }
616
+ }
617
+ ```
618
+
619
+ **Example package.json for Solana only (using @solana/kit)**:
620
+
621
+ ```json
622
+ {
623
+ "dependencies": {
624
+ "@phantom/browser-sdk": "^1.0.0",
625
+ "@solana/kit": "^2.0.0"
626
+ }
627
+ }
628
+ ```
629
+
630
+ **Example package.json for all networks (using @solana/web3.js)**:
631
+
632
+ ```json
633
+ {
634
+ "dependencies": {
635
+ "@phantom/browser-sdk": "^1.0.0",
636
+ "@solana/web3.js": "^1.87.0",
637
+ "viem": "^2.0.0",
638
+ "bitcoinjs-lib": "^6.1.0",
639
+ "@mysten/sui.js": "^0.50.0"
640
+ }
641
+ }
642
+ ```
643
+
644
+ **Example package.json for all networks (using @solana/kit)**:
645
+
646
+ ```json
647
+ {
648
+ "dependencies": {
649
+ "@phantom/browser-sdk": "^1.0.0",
650
+ "@solana/kit": "^2.0.0",
651
+ "viem": "^2.0.0",
652
+ "bitcoinjs-lib": "^6.1.0",
653
+ "@mysten/sui.js": "^0.50.0"
654
+ }
655
+ }
656
+ ```
657
+
658
+ 3. **Monitor bundle size**:
659
+ ```bash
660
+ # Analyze your bundle
661
+ npx webpack-bundle-analyzer dist/main.js
662
+ ```
663
+
664
+ ## Server Setup for Embedded Wallets
665
+
666
+ For embedded wallets, you need to set up a backend endpoint. Add the `serverUrl` parameter to your SDK configuration:
667
+
668
+ ```typescript
669
+ const sdk = new BrowserSDK({
670
+ providerType: "embedded",
671
+ addressTypes: [AddressType.solana],
672
+ apiBaseUrl: "https://api.phantom.com",
673
+ organizationId: "your-org-id",
674
+ serverUrl: "http://localhost:3000/api",
675
+ });
676
+ ```
677
+
678
+ ### Required Backend Endpoint
679
+
680
+ Your backend needs an endpoint that uses the server-sdk:
681
+
682
+ ```javascript
683
+ // server.js
684
+ const express = require("express");
685
+ const { ServerSDK } = require("@phantom/server-sdk");
686
+
687
+ const app = express();
688
+ app.use(express.json());
689
+
690
+ const serverSDK = new ServerSDK({
691
+ organizationId: process.env.ORGANIZATION_ID,
692
+ apiPrivateKey: process.env.PRIVATE_KEY,
693
+ apiBaseUrl: process.env.API_URL,
694
+ });
695
+
696
+ app.post("/api/organizations", async (req, res) => {
697
+ try {
698
+ const { userId } = req.body;
699
+
700
+ if (!userId) {
701
+ return res.status(400).json({ error: "userId is required" });
702
+ }
703
+
704
+ const organization = await serverSDK.getOrCreateChildOrganizationByTag({
705
+ tag: userId,
706
+ });
707
+
708
+ res.json({ organizationId: organization.id });
709
+ } catch (error) {
710
+ res.status(500).json({ error: "Failed to process request" });
711
+ }
712
+ });
713
+
714
+ app.listen(3000);
167
715
  ```