@phantom/browser-sdk 0.0.9 → 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 CHANGED
@@ -1,135 +1,296 @@
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(message, networkId)
214
+
215
+ Sign a message string.
216
+
217
+ ```typescript
218
+ const signature = await sdk.signMessage("Hello from Phantom!", NetworkId.SOLANA_MAINNET);
219
+ ```
60
220
 
61
- Once the `phantom.solana` object is initialized, you can access the following methods:
221
+ #### getAddresses()
62
222
 
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.
223
+ Get connected wallet addresses.
75
224
 
76
- ### Event Handling
225
+ ```typescript
226
+ const addresses = await sdk.getAddresses();
227
+ // Returns addresses matching configured AddressTypes
228
+ ```
77
229
 
78
- The SDK also allows you to listen for `connect`, `disconnect`, and `accountChanged` events:
230
+ #### disconnect()
79
231
 
80
- - `addEventListener(event: PhantomEventType, callback: PhantomEventCallback): () => void`
232
+ Disconnect from wallet and clear session.
81
233
 
82
- - Registers a callback that will be invoked when the specified event occurs.
83
- - For the `connect` event, the callback receives the public key (as a string) of the connected account.
84
- - For the `disconnect` event, the callback receives no arguments.
85
- - For the `accountChanged` event, the callback receives the new public key (as a string).
86
- - Returns a function that, when called, will unregister the callback.
87
- - Multiple callbacks can be registered for the same event.
234
+ ```typescript
235
+ await sdk.disconnect();
236
+ ```
88
237
 
89
- **Example:**
238
+ ## Transaction Examples
90
239
 
91
- ```typescript
92
- const phantom = createPhantom({ plugins: [createSolanaPlugin()] });
240
+ ### Solana Transactions
93
241
 
94
- const handleConnect = (address: string) => {
95
- console.log(`Wallet connected with public key: ${address}`);
96
- };
242
+ The SDK supports two different Solana transaction libraries. Choose based on your needs:
97
243
 
98
- const clearConnectListener = phantom.solana.addEventListener("connect", handleConnect);
244
+ #### Option 1: @solana/web3.js (Legacy Library)
99
245
 
100
- const handleAccountChanged = (newAddress: string) => {
101
- console.log(`Account changed to: ${newAddress}`);
102
- };
246
+ Traditional Solana library with broader ecosystem support.
103
247
 
104
- const clearAccountChangedListener = phantom.solana.addEventListener("accountChanged", handleAccountChanged);
248
+ ```bash
249
+ npm install @solana/web3.js
250
+ ```
105
251
 
106
- // To stop listening for a specific event:
107
- // clearConnectListener();
108
- // clearAccountChangedListener();
109
- ```
252
+ ```typescript
253
+ import { Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
254
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
255
+
256
+ // Create native Solana transaction
257
+ const transaction = new Transaction().add(
258
+ SystemProgram.transfer({
259
+ fromPubkey: new PublicKey(fromAddress),
260
+ toPubkey: new PublicKey(toAddress),
261
+ lamports: 0.001 * LAMPORTS_PER_SOL,
262
+ }),
263
+ );
110
264
 
111
- - `removeEventListener(event: PhantomEventType, callback: PhantomEventCallback): void`
265
+ // Send native transaction object - no encoding needed!
266
+ const result = await sdk.signAndSendTransaction({
267
+ networkId: NetworkId.SOLANA_MAINNET,
268
+ transaction: transaction,
269
+ });
112
270
 
113
- - Unregisters a previously registered callback for the specified event.
271
+ console.log("Transaction signature:", result.rawTransaction);
272
+ ```
114
273
 
115
- **Example:**
274
+ **VersionedTransaction with @solana/web3.js:**
116
275
 
117
- ```typescript
118
- const phantom = createPhantom({ plugins: [createSolanaPlugin()] });
276
+ ```typescript
277
+ import { VersionedTransaction } from "@solana/web3.js";
119
278
 
120
- const handleDisconnect = () => {
121
- console.log("Wallet disconnected");
122
- };
279
+ const versionedTx = new VersionedTransaction(message);
123
280
 
124
- phantom.solana.addEventListener("disconnect", handleDisconnect);
281
+ const result = await sdk.signAndSendTransaction({
282
+ networkId: NetworkId.SOLANA_DEVNET,
283
+ transaction: versionedTx,
284
+ });
285
+ ```
125
286
 
126
- // To stop listening for this specific disconnect event:
127
- // phantom.solana.removeEventListener("disconnect", handleDisconnect);
128
- ```
287
+ #### Option 2: @solana/kit (Modern Library)
129
288
 
130
- ### Creating a transaction
289
+ New high-performance Solana library with better TypeScript support.
131
290
 
132
- Phantom's SDK uses the `@solana/kit` library to create transactions. You can use the `createTransactionMessage` function to create a transaction message.
291
+ ```bash
292
+ npm install @solana/kit
293
+ ```
133
294
 
134
295
  ```typescript
135
296
  import {
@@ -141,20 +302,406 @@ import {
141
302
  address,
142
303
  compileTransaction,
143
304
  } from "@solana/kit";
305
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
144
306
 
145
- // Example: Sign and send a transaction
146
-
147
- const rpc = createSolanaRpc("https://my-rpc-url.com"); // Replace with your own RPC URL
148
-
307
+ // Create transaction with @solana/kit
308
+ const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
149
309
  const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
150
310
 
151
311
  const transactionMessage = pipe(
152
312
  createTransactionMessage({ version: 0 }),
153
- tx => setTransactionMessageFeePayer(address(userPublicKey as string), tx),
313
+ tx => setTransactionMessageFeePayer(address(userPublicKey), tx),
154
314
  tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
155
315
  );
156
316
 
157
317
  const transaction = compileTransaction(transactionMessage);
158
318
 
159
- const { signature } = await phantomInstance.solana.signAndSendTransaction(transaction);
319
+ const result = await sdk.signAndSendTransaction({
320
+ networkId: NetworkId.SOLANA_MAINNET,
321
+ transaction: transaction,
322
+ });
323
+ ```
324
+
325
+ ### Ethereum Transactions (with Viem)
326
+
327
+ ```typescript
328
+ import { parseEther, parseGwei, encodeFunctionData } from "viem";
329
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
330
+
331
+ // Simple ETH transfer
332
+ const result = await sdk.signAndSendTransaction({
333
+ networkId: NetworkId.ETHEREUM_MAINNET,
334
+ transaction: {
335
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
336
+ value: parseEther("1"), // 1 ETH
337
+ gas: 21000n,
338
+ gasPrice: parseGwei("20"), // 20 gwei
339
+ },
340
+ });
341
+
342
+ // EIP-1559 transaction with maxFeePerGas
343
+ const result = await sdk.signAndSendTransaction({
344
+ networkId: NetworkId.ETHEREUM_MAINNET,
345
+ transaction: {
346
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
347
+ value: parseEther("1"),
348
+ data: encodeFunctionData({
349
+ abi: tokenAbi,
350
+ functionName: "transfer",
351
+ args: ["0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E", parseEther("1")],
352
+ }),
353
+ gas: 50000n,
354
+ maxFeePerGas: parseGwei("30"), // 30 gwei
355
+ maxPriorityFeePerGas: parseGwei("2"), // 2 gwei
356
+ type: "eip1559",
357
+ },
358
+ });
359
+ ```
360
+
361
+ #### Other EVM Networks
362
+
363
+ ```typescript
364
+ // Polygon transaction
365
+ const result = await sdk.signAndSendTransaction({
366
+ networkId: NetworkId.POLYGON_MAINNET,
367
+ transaction: {
368
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
369
+ value: parseEther("1"), // 1 MATIC
370
+ gas: 21000n,
371
+ },
372
+ });
373
+
374
+ // Arbitrum transaction
375
+ const result = await sdk.signAndSendTransaction({
376
+ networkId: NetworkId.ARBITRUM_ONE,
377
+ transaction: {
378
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
379
+ value: parseEther("0.1"), // 0.1 ETH
380
+ gas: 21000n,
381
+ },
382
+ });
383
+ ```
384
+
385
+ ### Bitcoin Transactions
386
+
387
+ ```typescript
388
+ // Bitcoin transaction
389
+ const result = await sdk.signAndSendTransaction({
390
+ networkId: NetworkId.BITCOIN_MAINNET,
391
+ transaction: {
392
+ inputs: [
393
+ {
394
+ txid: "previous-transaction-id",
395
+ vout: 0,
396
+ scriptSig: "...",
397
+ },
398
+ ],
399
+ outputs: [
400
+ {
401
+ value: 50000, // satoshis
402
+ scriptPubKey: "76a914...88ac", // P2PKH script
403
+ },
404
+ ],
405
+ version: 2,
406
+ locktime: 0,
407
+ },
408
+ });
409
+
410
+ // Bitcoin testnet
411
+ const result = await sdk.signAndSendTransaction({
412
+ networkId: NetworkId.BITCOIN_TESTNET,
413
+ transaction: {
414
+ // ... transaction details
415
+ },
416
+ });
417
+ ```
418
+
419
+ ### Sui Transactions
420
+
421
+ ```typescript
422
+ import { TransactionBlock } from "@mysten/sui.js/transactions";
423
+
424
+ // Create Sui transaction block
425
+ const txb = new TransactionBlock();
426
+ txb.transferObjects([coin], recipientAddress);
427
+
428
+ const result = await sdk.signAndSendTransaction({
429
+ networkId: NetworkId.SUI_MAINNET,
430
+ transaction: {
431
+ kind: "moveCall", // or 'transferObject', 'transferSui', 'pay'
432
+ data: txb, // TransactionBlock from @mysten/sui.js
433
+ },
434
+ });
435
+
436
+ // Sui testnet
437
+ const result = await sdk.signAndSendTransaction({
438
+ networkId: NetworkId.SUI_TESTNET,
439
+ transaction: {
440
+ kind: "transferSui",
441
+ data: suiTransactionData,
442
+ },
443
+ });
444
+ ```
445
+
446
+ ## Network IDs Reference
447
+
448
+ Use the exported `NetworkId` enum for type safety:
449
+
450
+ ```typescript
451
+ import { NetworkId } from "@phantom/browser-sdk";
452
+ ```
453
+
454
+ ### Solana
455
+
456
+ - `NetworkId.SOLANA_MAINNET` - Solana Mainnet Beta
457
+ - `NetworkId.SOLANA_DEVNET` - Solana Devnet
458
+ - `NetworkId.SOLANA_TESTNET` - Solana Testnet
459
+
460
+ ### Ethereum/EVM
461
+
462
+ - `NetworkId.ETHEREUM_MAINNET` - Ethereum Mainnet
463
+ - `NetworkId.ETHEREUM_SEPOLIA` - Ethereum Sepolia Testnet
464
+ - `NetworkId.POLYGON_MAINNET` - Polygon Mainnet
465
+ - `NetworkId.ARBITRUM_ONE` - Arbitrum One
466
+ - `NetworkId.OPTIMISM_MAINNET` - Optimism Mainnet
467
+ - `NetworkId.BASE_MAINNET` - Base Mainnet
468
+
469
+ ### Bitcoin
470
+
471
+ - `NetworkId.BITCOIN_MAINNET` - Bitcoin Mainnet
472
+ - `NetworkId.BITCOIN_TESTNET` - Bitcoin Testnet
473
+
474
+ ### Sui
475
+
476
+ - `NetworkId.SUI_MAINNET` - Sui Mainnet
477
+ - `NetworkId.SUI_TESTNET` - Sui Testnet
478
+ - `NetworkId.SUI_DEVNET` - Sui Devnet
479
+
480
+ ## Advanced Usage
481
+
482
+ ### Multi-Chain Application
483
+
484
+ ```typescript
485
+ import { BrowserSDK, AddressType } from "@phantom/browser-sdk";
486
+
487
+ const sdk = new BrowserSDK({
488
+ addressTypes: [AddressType.solana, AddressType.ethereum, AddressType.sui],
489
+ apiBaseUrl: "https://api.phantom.com",
490
+ organizationId: "your-org-id",
491
+ });
492
+
493
+ class MultiChainWallet {
494
+ async sendSolana(amount: number, recipient: string) {
495
+ const transaction = new Transaction().add(
496
+ SystemProgram.transfer({
497
+ fromPubkey: new PublicKey(this.solanaAddress),
498
+ toPubkey: new PublicKey(recipient),
499
+ lamports: amount * LAMPORTS_PER_SOL,
500
+ }),
501
+ );
502
+
503
+ return await sdk.signAndSendTransaction({
504
+ networkId: NetworkId.SOLANA_MAINNET,
505
+ transaction,
506
+ });
507
+ }
508
+
509
+ async sendEthereum(amount: string, recipient: string) {
510
+ return await sdk.signAndSendTransaction({
511
+ networkId: NetworkId.ETHEREUM_MAINNET,
512
+ transaction: {
513
+ to: recipient,
514
+ value: parseEther(amount),
515
+ gas: 21000n,
516
+ },
517
+ });
518
+ }
519
+
520
+ async sendSui(coinId: string, recipient: string) {
521
+ const txb = new TransactionBlock();
522
+ txb.transferObjects([coinId], recipient);
523
+
524
+ return await sdk.signAndSendTransaction({
525
+ networkId: NetworkId.SUI_MAINNET,
526
+ transaction: {
527
+ kind: "transferObject",
528
+ data: txb,
529
+ },
530
+ });
531
+ }
532
+ }
533
+ ```
534
+
535
+ ### Error Handling
536
+
537
+ ```typescript
538
+ try {
539
+ const result = await sdk.signAndSendTransaction({
540
+ networkId: NetworkId.SOLANA_MAINNET,
541
+ transaction: myTransaction,
542
+ });
543
+ console.log("Success:", result);
544
+ } catch (error) {
545
+ if (error.message.includes("User rejected")) {
546
+ console.log("User cancelled the transaction");
547
+ } else if (error.message.includes("insufficient funds")) {
548
+ console.log("Not enough balance");
549
+ } else {
550
+ console.error("Transaction failed:", error);
551
+ }
552
+ }
553
+ ```
554
+
555
+ ### Bundle Optimization Tips
556
+
557
+ 1. **Only include networks you need**:
558
+
559
+ ```typescript
560
+ // Good: Only Solana (~250KB)
561
+ addressTypes: [AddressType.solana];
562
+
563
+ // Avoid: All networks if not needed (~800KB+)
564
+ addressTypes: [AddressType.solana, AddressType.ethereum, AddressType.sui, AddressType.bitcoinSegwit];
565
+ ```
566
+
567
+ 2. **Install dependencies based on enabled networks**:
568
+
569
+ | AddressType | Required Dependencies | Bundle Size |
570
+ | --------------------------- | ---------------------------------- | ----------- |
571
+ | `AddressType.solana` | `@solana/web3.js` OR `@solana/kit` | ~250KB |
572
+ | `AddressType.ethereum` | `viem` | ~300KB |
573
+ | `AddressType.bitcoinSegwit` | `bitcoinjs-lib` | ~200KB |
574
+ | `AddressType.sui` | `@mysten/sui.js` | ~250KB |
575
+
576
+ **Example package.json for Solana + Ethereum (using @solana/web3.js)**:
577
+
578
+ ```json
579
+ {
580
+ "dependencies": {
581
+ "@phantom/browser-sdk": "^1.0.0",
582
+ "@solana/web3.js": "^1.87.0",
583
+ "viem": "^2.0.0"
584
+ }
585
+ }
586
+ ```
587
+
588
+ **Example package.json for Solana + Ethereum (using @solana/kit)**:
589
+
590
+ ```json
591
+ {
592
+ "dependencies": {
593
+ "@phantom/browser-sdk": "^1.0.0",
594
+ "@solana/kit": "^2.0.0",
595
+ "viem": "^2.0.0"
596
+ }
597
+ }
598
+ ```
599
+
600
+ **Example package.json for Solana only (using @solana/web3.js)**:
601
+
602
+ ```json
603
+ {
604
+ "dependencies": {
605
+ "@phantom/browser-sdk": "^1.0.0",
606
+ "@solana/web3.js": "^1.87.0"
607
+ }
608
+ }
609
+ ```
610
+
611
+ **Example package.json for Solana only (using @solana/kit)**:
612
+
613
+ ```json
614
+ {
615
+ "dependencies": {
616
+ "@phantom/browser-sdk": "^1.0.0",
617
+ "@solana/kit": "^2.0.0"
618
+ }
619
+ }
620
+ ```
621
+
622
+ **Example package.json for all networks (using @solana/web3.js)**:
623
+
624
+ ```json
625
+ {
626
+ "dependencies": {
627
+ "@phantom/browser-sdk": "^1.0.0",
628
+ "@solana/web3.js": "^1.87.0",
629
+ "viem": "^2.0.0",
630
+ "bitcoinjs-lib": "^6.1.0",
631
+ "@mysten/sui.js": "^0.50.0"
632
+ }
633
+ }
634
+ ```
635
+
636
+ **Example package.json for all networks (using @solana/kit)**:
637
+
638
+ ```json
639
+ {
640
+ "dependencies": {
641
+ "@phantom/browser-sdk": "^1.0.0",
642
+ "@solana/kit": "^2.0.0",
643
+ "viem": "^2.0.0",
644
+ "bitcoinjs-lib": "^6.1.0",
645
+ "@mysten/sui.js": "^0.50.0"
646
+ }
647
+ }
648
+ ```
649
+
650
+ 3. **Monitor bundle size**:
651
+ ```bash
652
+ # Analyze your bundle
653
+ npx webpack-bundle-analyzer dist/main.js
654
+ ```
655
+
656
+ ## Server Setup for Embedded Wallets
657
+
658
+ For embedded wallets, you need to set up a backend endpoint. Add the `serverUrl` parameter to your SDK configuration:
659
+
660
+ ```typescript
661
+ const sdk = new BrowserSDK({
662
+ providerType: "embedded",
663
+ addressTypes: [AddressType.solana],
664
+ apiBaseUrl: "https://api.phantom.com",
665
+ organizationId: "your-org-id",
666
+ serverUrl: "http://localhost:3000/api",
667
+ });
668
+ ```
669
+
670
+ ### Required Backend Endpoint
671
+
672
+ Your backend needs an endpoint that uses the server-sdk:
673
+
674
+ ```javascript
675
+ // server.js
676
+ const express = require("express");
677
+ const { ServerSDK } = require("@phantom/server-sdk");
678
+
679
+ const app = express();
680
+ app.use(express.json());
681
+
682
+ const serverSDK = new ServerSDK({
683
+ organizationId: process.env.ORGANIZATION_ID,
684
+ apiPrivateKey: process.env.PRIVATE_KEY,
685
+ apiBaseUrl: process.env.API_URL,
686
+ });
687
+
688
+ app.post("/api/organizations", async (req, res) => {
689
+ try {
690
+ const { userId } = req.body;
691
+
692
+ if (!userId) {
693
+ return res.status(400).json({ error: "userId is required" });
694
+ }
695
+
696
+ const organization = await serverSDK.getOrCreateChildOrganizationByTag({
697
+ tag: userId,
698
+ });
699
+
700
+ res.json({ organizationId: organization.id });
701
+ } catch (error) {
702
+ res.status(500).json({ error: "Failed to process request" });
703
+ }
704
+ });
705
+
706
+ app.listen(3000);
160
707
  ```